diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 0000000000000..1d93939e23360 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,16 @@ +--- +name: Documentation problem +about: Create a report for a documentation problem. +labels: A-docs +--- +<!-- +Thank you for finding a documentation problem! 📚 + +Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present. + +--> + +### Location + +### Summary + diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md index 32fccfcfb1696..91c06402ca10a 100644 --- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md @@ -50,7 +50,7 @@ If the feature is changed later, please add those PRs here as well. --> - [ ] Implementation: #... -- [ ] Final comment period (FCP) +- [ ] Final comment period (FCP)[^1] - [ ] Stabilization PR <!-- @@ -81,3 +81,5 @@ Zulip, or the internals forum) here. --> - None yet. + +[^1]: https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7be9978c0bc5..6d9e249ee44ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -410,7 +410,7 @@ jobs: - 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: python x.py dist + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl - name: dist-i686-msvc diff --git a/.gitignore b/.gitignore index ec6cb6ed2e4d3..a6625ac2ac4a1 100644 --- a/.gitignore +++ b/.gitignore @@ -46,8 +46,6 @@ no_llvm_build /unicode-downloads /target /src/tools/x/target -# Generated by compiletest for incremental -/tmp/ # Created by default with `src/ci/docker/run.sh` /obj/ diff --git a/.gitmodules b/.gitmodules index 21bce3c7fa06b..a524098845a48 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,7 +34,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/14.0-2022-03-22 + branch = rustc/14.0-2022-06-20 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index 1108c1f4d4c20..e8081b5a6574d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,32 +215,6 @@ dependencies = [ "byte-tools", ] -[[package]] -name = "bootstrap" -version = "0.0.0" -dependencies = [ - "cc", - "cmake", - "filetime", - "getopts", - "hex 0.4.2", - "ignore", - "libc", - "num_cpus", - "once_cell", - "opener", - "pretty_assertions 0.7.2", - "serde", - "serde_json", - "sha2", - "sysinfo", - "tar", - "toml", - "walkdir", - "winapi", - "xz2", -] - [[package]] name = "bstr" version = "0.2.13" @@ -324,7 +298,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.64.0" +version = "0.65.0" dependencies = [ "anyhow", "atty", @@ -333,7 +307,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap 3.2.5", + "clap", "crates-io", "crossbeam-utils", "curl", @@ -471,7 +445,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.1.4" +version = "0.2.1" dependencies = [ "anyhow", "core-foundation", @@ -598,22 +572,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", - "yaml-rust 0.3.5", -] - [[package]] name = "clap" version = "3.2.5" @@ -626,9 +584,9 @@ dependencies = [ "clap_lex", "indexmap", "once_cell", - "strsim 0.10.0", + "strsim", "termcolor", - "textwrap 0.15.0", + "textwrap", ] [[package]] @@ -637,7 +595,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25" dependencies = [ - "clap 3.2.5", + "clap", ] [[package]] @@ -664,7 +622,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.63" +version = "0.1.64" dependencies = [ "clippy_lints", "clippy_utils", @@ -687,6 +645,7 @@ dependencies = [ "termize", "tester", "tokio", + "toml", ] [[package]] @@ -694,7 +653,7 @@ name = "clippy_dev" version = "0.0.1" dependencies = [ "aho-corasick", - "clap 3.2.5", + "clap", "indoc", "itertools", "opener", @@ -705,10 +664,9 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.63" +version = "0.1.64" dependencies = [ "cargo_metadata", - "clippy_dev", "clippy_utils", "if_chain", "itertools", @@ -728,22 +686,13 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.63" +version = "0.1.64" dependencies = [ "arrayvec", "if_chain", "rustc-semver", ] -[[package]] -name = "cmake" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" -dependencies = [ - "cc", -] - [[package]] name = "colored" version = "2.0.0" @@ -1023,9 +972,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.15" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ "quote", "syn", @@ -1277,7 +1226,7 @@ name = "expand-yaml-anchors" version = "0.1.0" dependencies = [ "yaml-merge-keys", - "yaml-rust 0.4.4", + "yaml-rust", ] [[package]] @@ -1709,9 +1658,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", "compiler_builtins", @@ -1873,12 +1822,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown 0.12.3", "rustc-rayon", "serde", ] @@ -1897,7 +1846,7 @@ name = "installer" version = "0.0.0" dependencies = [ "anyhow", - "clap 2.34.0", + "clap", "flate2", "lazy_static", "num_cpus", @@ -2345,7 +2294,7 @@ dependencies = [ "ammonia", "anyhow", "chrono", - "clap 3.2.5", + "clap", "clap_complete", "elasticlunr-rs", "env_logger 0.7.1", @@ -2365,20 +2314,6 @@ dependencies = [ "topological-sort", ] -[[package]] -name = "measureme" -version = "9.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" -dependencies = [ - "log", - "memmap2", - "parking_lot 0.11.2", - "perf-event-open-sys", - "rustc-hash", - "smallvec", -] - [[package]] name = "measureme" version = "10.0.0" @@ -2477,7 +2412,7 @@ dependencies = [ "lazy_static", "libc", "log", - "measureme 9.1.2", + "measureme", "rand 0.8.5", "regex", "rustc-workspace-hack", @@ -2579,7 +2514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "indexmap", "memchr", ] @@ -2666,9 +2601,9 @@ checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" [[package]] name = "os_info" -version = "3.0.7" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac91020bfed8cc3f8aa450d4c3b5fa1d3373fc091c8a92009f3b27749d5a227" +checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62" dependencies = [ "log", "serde", @@ -2683,9 +2618,9 @@ checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" [[package]] name = "output_vt100" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ "winapi", ] @@ -2944,18 +2879,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "pretty_assertions" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "pretty_assertions" version = "1.2.1" @@ -3101,7 +3024,6 @@ name = "racer" version = "2.2.2" dependencies = [ "bitflags", - "clap 2.34.0", "derive_more", "env_logger 0.7.1", "humantime 2.0.1", @@ -3325,7 +3247,7 @@ dependencies = [ "difference", "env_logger 0.9.0", "futures 0.3.19", - "heck 0.3.1", + "heck 0.4.0", "home", "itertools", "jsonrpc-core", @@ -3447,7 +3369,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.34.0", + "clap", "env_logger 0.7.1", "mdbook", ] @@ -3535,13 +3457,14 @@ version = "1.0.0" dependencies = [ "bstr", "byteorder", - "clap 3.2.5", + "clap", "crossbeam-utils", "libc", "libz-sys", "proc-macro2", "quote", "rand_core 0.5.1", + "regex", "serde", "serde_json", "smallvec", @@ -3657,6 +3580,7 @@ dependencies = [ "rustc_index", "rustc_infer", "rustc_lexer", + "rustc_macros", "rustc_middle", "rustc_mir_dataflow", "rustc_serialize", @@ -3700,7 +3624,7 @@ dependencies = [ "cstr", "libc", "libloading", - "measureme 10.0.0", + "measureme", "rustc-demangle", "rustc_ast", "rustc_attr", @@ -3798,7 +3722,7 @@ dependencies = [ "indexmap", "jobserver", "libc", - "measureme 10.0.0", + "measureme", "memmap2", "parking_lot 0.11.2", "rustc-hash", @@ -3874,6 +3798,7 @@ dependencies = [ "atty", "rustc_data_structures", "rustc_error_messages", + "rustc_hir", "rustc_lint_defs", "rustc_macros", "rustc_serialize", @@ -3930,6 +3855,7 @@ name = "rustc_hir" version = "0.0.0" dependencies = [ "odht", + "rustc_arena", "rustc_ast", "rustc_data_structures", "rustc_error_messages", @@ -4043,7 +3969,6 @@ dependencies = [ "rustc_ty_utils", "rustc_typeck", "smallvec", - "tempfile", "tracing", "winapi", ] @@ -4070,6 +3995,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_macros", "rustc_middle", "rustc_parse_format", "rustc_session", @@ -4153,6 +4079,7 @@ dependencies = [ "rustc_type_ir", "smallvec", "snap", + "tempfile", "tracing", ] @@ -4312,6 +4239,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_lexer", + "rustc_macros", "rustc_middle", "rustc_serialize", "rustc_session", @@ -4342,6 +4270,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4354,7 +4283,7 @@ dependencies = [ name = "rustc_query_impl" version = "0.0.0" dependencies = [ - "measureme 10.0.0", + "measureme", "rustc-rayon-core", "rustc_ast", "rustc_data_structures", @@ -4586,6 +4515,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_index", "rustc_infer", "rustc_middle", "rustc_session", @@ -4712,13 +4642,13 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.0" +version = "1.5.1" dependencies = [ "annotate-snippets 0.9.1", "anyhow", "bytecount", "cargo_metadata", - "clap 3.2.5", + "clap", "derive-new", "diff", "dirs", @@ -4968,9 +4898,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "snap" @@ -5048,7 +4978,7 @@ dependencies = [ "core", "dlmalloc", "fortanix-sgx-abi", - "hashbrown 0.12.0", + "hashbrown 0.12.3", "hermit-abi 0.2.0", "libc", "miniz_oxide", @@ -5109,12 +5039,6 @@ dependencies = [ "vte", ] -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" @@ -5162,21 +5086,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "sysinfo" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a8e71535da31837213ac114531d31def75d7aebd133264e420a3451fa7f703" -dependencies = [ - "cfg-if 1.0.0", - "core-foundation-sys", - "libc", - "ntapi", - "once_cell", - "rayon", - "winapi", -] - [[package]] name = "tar" version = "0.4.38" @@ -5270,15 +5179,6 @@ dependencies = [ "term", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.15.0" @@ -5553,7 +5453,7 @@ dependencies = [ "colored", "crossbeam", "lazy_static", - "pretty_assertions 1.2.1", + "pretty_assertions", "regex", "rustc_version", "serde", @@ -5799,12 +5699,6 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "vergen" version = "5.1.0" @@ -5963,15 +5857,9 @@ checksum = "fd236a7dc9bb598f349fe4a8754f49181fee50284daa15cd1ba652d722280004" dependencies = [ "lazy_static", "thiserror", - "yaml-rust 0.4.4", + "yaml-rust", ] -[[package]] -name = "yaml-rust" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" - [[package]] name = "yaml-rust" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 4e78399606445..ed024192c1503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,5 @@ [workspace] -default-members = ["src/bootstrap"] members = [ - "src/bootstrap", "compiler/rustc", "library/std", "library/test", @@ -44,6 +42,7 @@ exclude = [ "build", "compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc", + "src/bootstrap", "src/test/rustdoc-gui", # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`. "obj", @@ -97,15 +96,6 @@ gimli.debug = 0 miniz_oxide.debug = 0 object.debug = 0 -# The only package that ever uses debug builds is bootstrap. -# We care a lot about bootstrap's compile times, so don't include debug info for -# dependencies, only bootstrap itself. -[profile.dev] -debug = 0 -[profile.dev.package] -# Only use debuginfo=1 to further reduce compile times. -bootstrap.debug = 1 - # We want the RLS to use the version of Cargo that we've got vendored in this # repository to ensure that the same exact version of Cargo is used by both the # RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository diff --git a/RELEASES.md b/RELEASES.md index 3d88891ad215c..8154eab20599a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5,7 +5,7 @@ Language -------- - [Stabilize `#[derive(Default)]` on enums with a `#[default]` variant][94457] -- [Stop validating some checks in dead code after functions with uninhabited return types][93313] +- [Teach flow sensitive checks that visibly uninhabited call expressions never return][93313] - [Fix constants not getting dropped if part of a diverging expression][94775] - [Support unit struct/enum variant in destructuring assignment][95380] - [Remove mutable_borrow_reservation_conflict lint and allow the code pattern][96268] @@ -29,7 +29,6 @@ Compiler Libraries --------- -- [Move `CStr` to libcore, and `CString` to liballoc][94079] - [Windows: Use a pipe relay for chaining pipes][95841] - [Replace Linux Mutex and Condvar with futex based ones.][95035] - [Replace RwLock by a futex based one on Linux][95801] @@ -76,8 +75,11 @@ Compatibility Notes - `cargo test` now passes `--target` to `rustdoc` if the specified target is the same as the host target. [#10594](https://github.com/rust-lang/cargo/pull/10594) +- [rustdoc: doctests are now run on unexported `macro_rules!` macros, matching other private items][96630] - [rustdoc: Remove .woff font files][96279] - [Enforce Copy bounds for repeat elements while considering lifetimes][95819] +- [Windows: Fix potentinal unsoundness by aborting if `File` reads or writes cannot + complete synchronously][95469]. Internal Changes ---------------- @@ -90,7 +92,6 @@ and related tools. [93313]: https://github.com/rust-lang/rust/pull/93313/ [93969]: https://github.com/rust-lang/rust/pull/93969/ -[94079]: https://github.com/rust-lang/rust/pull/94079/ [94206]: https://github.com/rust-lang/rust/pull/94206/ [94457]: https://github.com/rust-lang/rust/pull/94457/ [94775]: https://github.com/rust-lang/rust/pull/94775/ @@ -100,6 +101,7 @@ and related tools. [95372]: https://github.com/rust-lang/rust/pull/95372/ [95380]: https://github.com/rust-lang/rust/pull/95380/ [95431]: https://github.com/rust-lang/rust/pull/95431/ +[95469]: https://github.com/rust-lang/rust/pull/95469/ [95705]: https://github.com/rust-lang/rust/pull/95705/ [95801]: https://github.com/rust-lang/rust/pull/95801/ [95819]: https://github.com/rust-lang/rust/pull/95819/ @@ -111,6 +113,7 @@ and related tools. [96393]: https://github.com/rust-lang/rust/pull/96393/ [96436]: https://github.com/rust-lang/rust/pull/96436/ [96557]: https://github.com/rust-lang/rust/pull/96557/ +[96630]: https://github.com/rust-lang/rust/pull/96630/ [`bool::then_some`]: https://doc.rust-lang.org/stable/std/primitive.bool.html#method.then_some [`f32::total_cmp`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.total_cmp diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs index 24c06c0ddbf6c..39cf3e094c823 100644 --- a/compiler/rustc/build.rs +++ b/compiler/rustc/build.rs @@ -5,6 +5,9 @@ fn main() { let target_env = env::var("CARGO_CFG_TARGET_ENV"); if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() { set_windows_exe_options(); + } else { + // Avoid rerunning the build script every time. + println!("cargo:rerun-if-changed=build.rs"); } } diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml index bb01d4f51b899..98305201bc943 100644 --- a/compiler/rustc_apfloat/Cargo.toml +++ b/compiler/rustc_apfloat/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] bitflags = "1.2.1" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index ee3a7b51b699a..5c2aee6b47f9a 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -4,4 +4,4 @@ version = "0.0.0" edition = "2021" [dependencies] -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 62995dfd2e2f0..a5f1cbc96daa7 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -19,6 +19,7 @@ #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] +#![feature(ptr_const_cast)] use smallvec::SmallVec; @@ -27,7 +28,7 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::marker::{PhantomData, Send}; use std::mem::{self, MaybeUninit}; -use std::ptr; +use std::ptr::{self, NonNull}; use std::slice; #[inline(never)] @@ -55,15 +56,24 @@ pub struct TypedArena<T> { struct ArenaChunk<T = u8> { /// The raw storage for the arena chunk. - storage: Box<[MaybeUninit<T>]>, + storage: NonNull<[MaybeUninit<T>]>, /// The number of valid entries in the chunk. entries: usize, } +unsafe impl<#[may_dangle] T> Drop for ArenaChunk<T> { + fn drop(&mut self) { + unsafe { Box::from_raw(self.storage.as_mut()) }; + } +} + impl<T> ArenaChunk<T> { #[inline] unsafe fn new(capacity: usize) -> ArenaChunk<T> { - ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } + ArenaChunk { + storage: NonNull::new(Box::into_raw(Box::new_uninit_slice(capacity))).unwrap(), + entries: 0, + } } /// Destroys this arena chunk. @@ -72,14 +82,15 @@ impl<T> ArenaChunk<T> { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena<u8> takes linear time. if mem::needs_drop::<T>() { - ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len])); + let slice = &mut *(self.storage.as_mut()); + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len])); } } // Returns a pointer to the first allocated object. #[inline] fn start(&mut self) -> *mut T { - MaybeUninit::slice_as_mut_ptr(&mut self.storage) + self.storage.as_ptr() as *mut T } // Returns a pointer to the end of the allocated space. @@ -90,7 +101,7 @@ impl<T> ArenaChunk<T> { // A pointer as large as possible for zero-sized elements. ptr::invalid_mut(!0) } else { - self.start().add(self.storage.len()) + self.start().add((*self.storage.as_ptr()).len()) } } } @@ -274,7 +285,7 @@ impl<T> TypedArena<T> { // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2); + new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / elem_size / 2); new_cap *= 2; } else { new_cap = PAGE / elem_size; @@ -382,7 +393,7 @@ impl DroplessArena { // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2); + new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / 2); new_cap *= 2; } else { new_cap = PAGE; diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs index 911e577c1edc7..ad61464343a4a 100644 --- a/compiler/rustc_arena/src/tests.rs +++ b/compiler/rustc_arena/src/tests.rs @@ -79,7 +79,11 @@ fn test_arena_alloc_nested() { #[test] pub fn test_copy() { let arena = TypedArena::default(); - for _ in 0..100000 { + #[cfg(not(miri))] + const N: usize = 100000; + #[cfg(miri)] + const N: usize = 1000; + for _ in 0..N { arena.alloc(Point { x: 1, y: 2, z: 3 }); } } @@ -106,7 +110,11 @@ struct Noncopy { #[test] pub fn test_noncopy() { let arena = TypedArena::default(); - for _ in 0..100000 { + #[cfg(not(miri))] + const N: usize = 100000; + #[cfg(miri)] + const N: usize = 1000; + for _ in 0..N { arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] }); } } @@ -114,7 +122,11 @@ pub fn test_noncopy() { #[test] pub fn test_typed_arena_zero_sized() { let arena = TypedArena::default(); - for _ in 0..100000 { + #[cfg(not(miri))] + const N: usize = 100000; + #[cfg(miri)] + const N: usize = 1000; + for _ in 0..N { arena.alloc(()); } } @@ -124,7 +136,11 @@ pub fn test_typed_arena_clear() { let mut arena = TypedArena::default(); for _ in 0..10 { arena.clear(); - for _ in 0..10000 { + #[cfg(not(miri))] + const N: usize = 10000; + #[cfg(miri)] + const N: usize = 100; + for _ in 0..N { arena.alloc(Point { x: 1, y: 2, z: 3 }); } } diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 58b967a370415..9822e9864e210 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -14,5 +14,5 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } bitflags = "1.2.1" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e5b61d7000a32..ac2328a582418 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1390,7 +1390,7 @@ pub enum ExprKind { /// A closure (e.g., `move |a, b, c| a + b + c`). /// /// The final span is the span of the argument block `|...|`. - Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span), + Closure(ClosureBinder, CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span), /// A block (`'label: { ... }`). Block(P<Block>, Option<Label>), /// An async block (`async move { ... }`). @@ -1518,6 +1518,31 @@ pub enum Movability { Movable, } +/// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum ClosureBinder { + /// The binder is not present, all closure lifetimes are inferred. + NotPresent, + /// The binder is present. + For { + /// Span of the whole `for<>` clause + /// + /// ```text + /// for<'a, 'b> |_: &'a (), _: &'b ()| { ... } + /// ^^^^^^^^^^^ -- this + /// ``` + span: Span, + + /// Lifetimes in the `for<>` closure + /// + /// ```text + /// for<'a, 'b> |_: &'a (), _: &'b ()| { ... } + /// ^^^^^^ -- this + /// ``` + generic_params: P<[GenericParam]>, + }, +} + /// Represents a macro invocation. The `path` indicates which macro /// is being invoked, and the `args` are arguments passed to it. #[derive(Clone, Encodable, Decodable, Debug)] @@ -2036,6 +2061,14 @@ impl TyKind { pub fn is_unit(&self) -> bool { matches!(self, TyKind::Tup(tys) if tys.is_empty()) } + + pub fn is_simple_path(&self) -> Option<Symbol> { + if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 { + Some(segments[0].ident.name) + } else { + None + } + } } /// Syntax used to declare a trait object. @@ -2667,13 +2700,16 @@ impl Item { #[derive(Clone, Copy, Encodable, Decodable, Debug)] pub enum Extern { None, - Implicit, - Explicit(StrLit), + Implicit(Span), + Explicit(StrLit, Span), } impl Extern { - pub fn from_abi(abi: Option<StrLit>) -> Extern { - abi.map_or(Extern::Implicit, Extern::Explicit) + pub fn from_abi(abi: Option<StrLit>, span: Span) -> Extern { + match abi { + Some(name) => Extern::Explicit(name, span), + None => Extern::Implicit(span), + } } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 4b94ec0d6d8f4..838f77512c5af 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -14,7 +14,7 @@ #![feature(const_trait_impl)] #![feature(if_let_guard)] #![feature(label_break_value)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(slice_internals)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 85bb52964865b..d933ea2da9ed7 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -125,6 +125,10 @@ pub trait MutVisitor: Sized { noop_visit_asyncness(a, self); } + fn visit_closure_binder(&mut self, b: &mut ClosureBinder) { + noop_visit_closure_binder(b, self); + } + fn visit_block(&mut self, b: &mut P<Block>) { noop_visit_block(b, self); } @@ -825,6 +829,17 @@ pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) { } } +pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) { + match binder { + ClosureBinder::NotPresent => {} + ClosureBinder::For { span: _, generic_params } => { + let mut vec = std::mem::take(generic_params).into_vec(); + vec.flat_map_in_place(|param| vis.flat_map_generic_param(param)); + *generic_params = P::from_vec(vec); + } + } +} + pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) { match asyncness { Async::Yes { span: _, closure_id, return_impl_trait_id } => { @@ -1336,7 +1351,8 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_expr(expr); arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); } - ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => { + ExprKind::Closure(binder, _capture_by, asyncness, _movability, decl, body, span) => { + vis.visit_closure_binder(binder); vis.visit_asyncness(asyncness); vis.visit_fn_decl(decl); vis.visit_expr(body); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 2ce8590d7718f..3f830acbf27a6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -56,14 +56,14 @@ pub enum FnKind<'a> { Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), /// E.g., `|x, y| body`. - Closure(&'a FnDecl, &'a Expr), + Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr), } impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header), - FnKind::Closure(_, _) => None, + FnKind::Closure(_, _, _) => None, } } @@ -77,7 +77,7 @@ impl<'a> FnKind<'a> { pub fn decl(&self) -> &'a FnDecl { match self { FnKind::Fn(_, _, sig, _, _, _) => &sig.decl, - FnKind::Closure(decl, _) => decl, + FnKind::Closure(_, decl, _) => decl, } } @@ -155,6 +155,9 @@ pub trait Visitor<'ast>: Sized { fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) } + fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) { + walk_closure_binder(self, b) + } fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { walk_where_predicate(self, p) } @@ -636,6 +639,15 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); } +pub fn walk_closure_binder<'a, V: Visitor<'a>>(visitor: &mut V, binder: &'a ClosureBinder) { + match binder { + ClosureBinder::NotPresent => {} + ClosureBinder::For { generic_params, span: _ } => { + walk_list!(visitor, visit_generic_param, generic_params) + } + } +} + pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) { match *predicate { WherePredicate::BoundPredicate(WhereBoundPredicate { @@ -682,7 +694,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa walk_fn_decl(visitor, &sig.decl); walk_list!(visitor, visit_block, body); } - FnKind::Closure(decl, body) => { + FnKind::Closure(binder, decl, body) => { + visitor.visit_closure_binder(binder); walk_fn_decl(visitor, decl); visitor.visit_expr(body); } @@ -856,8 +869,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => { - visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id) + ExprKind::Closure(ref binder, _, _, _, ref decl, ref body, _decl_span) => { + visitor.visit_fn(FnKind::Closure(binder, decl, body), expression.span, expression.id) } ExprKind::Block(ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index e344d8a7637c4..39ba62ef2ffc5 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -20,4 +20,4 @@ rustc_span = { path = "../rustc_span" } rustc_errors = { path = "../rustc_errors" } rustc_session = { path = "../rustc_session" } rustc_ast = { path = "../rustc_ast" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index aab9b90e4b7e5..0e395d7033586 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -24,10 +24,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> &'hir hir::InlineAsm<'hir> { // Rustdoc needs to support asm! from foreign architectures: don't try // lowering the register constraints in this case. - let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch }; - if asm_arch.is_none() && !self.sess.opts.actually_rustdoc { - struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target") - .emit(); + let asm_arch = + if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch }; + if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc { + struct_span_err!( + self.tcx.sess, + sp, + E0472, + "inline assembly is unsupported on this target" + ) + .emit(); } if let Some(asm_arch) = asm_arch { // Inline assembly is currently only stable for these architectures. @@ -40,9 +46,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::RiscV32 | asm::InlineAsmArch::RiscV64 ); - if !is_stable && !self.sess.features_untracked().asm_experimental_arch { + if !is_stable && !self.tcx.features().asm_experimental_arch { feature_err( - &self.sess.parse_sess, + &self.tcx.sess.parse_sess, sym::asm_experimental_arch, sp, "inline assembly is not stable yet on this architecture", @@ -52,17 +58,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)) - && !self.sess.opts.actually_rustdoc + && !self.tcx.sess.opts.actually_rustdoc { - self.sess + self.tcx + .sess .struct_span_err(sp, "the `att_syntax` option is only supported on x86") .emit(); } - if asm.options.contains(InlineAsmOptions::MAY_UNWIND) - && !self.sess.features_untracked().asm_unwind - { + if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { feature_err( - &self.sess.parse_sess, + &self.tcx.sess.parse_sess, sym::asm_unwind, sp, "the `may_unwind` option is unstable", @@ -73,12 +78,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut clobber_abis = FxHashMap::default(); if let Some(asm_arch) = asm_arch { for (abi_name, abi_span) in &asm.clobber_abis { - match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) { + match asm::InlineAsmClobberAbi::parse(asm_arch, &self.tcx.sess.target, *abi_name) { Ok(abi) => { // If the abi was already in the list, emit an error match clobber_abis.get(&abi) { Some((prev_name, prev_sp)) => { - let mut err = self.sess.struct_span_err( + let mut err = self.tcx.sess.struct_span_err( *abi_span, &format!("`{}` ABI specified multiple times", prev_name), ); @@ -86,7 +91,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Multiple different abi names may actually be the same ABI // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI - let source_map = self.sess.source_map(); + let source_map = self.tcx.sess.source_map(); if source_map.span_to_snippet(*prev_sp) != source_map.span_to_snippet(*abi_span) { @@ -101,7 +106,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } Err(&[]) => { - self.sess + self.tcx + .sess .struct_span_err( *abi_span, "`clobber_abi` is not supported on this target", @@ -109,8 +115,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } Err(supported_abis) => { - let mut err = - self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); + let mut err = self + .tcx + .sess + .struct_span_err(*abi_span, "invalid ABI for `clobber_abi`"); let mut abis = format!("`{}`", supported_abis[0]); for m in &supported_abis[1..] { let _ = write!(abis, ", `{}`", m); @@ -128,7 +136,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Lower operands to HIR. We use dummy register classes if an error // occurs during lowering because we still need to be able to produce a // valid HIR. - let sess = self.sess; + let sess = self.tcx.sess; let mut operands: Vec<_> = asm .operands .iter() @@ -184,9 +192,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Const { ref anon_const } => { - if !self.sess.features_untracked().asm_const { + if !self.tcx.features().asm_const { feature_err( - &self.sess.parse_sess, + &sess.parse_sess, sym::asm_const, *op_sp, "const operands for inline assembly are unstable", @@ -198,9 +206,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Sym { ref sym } => { - if !self.sess.features_untracked().asm_sym { + if !self.tcx.features().asm_sym { feature_err( - &self.sess.parse_sess, + &sess.parse_sess, sym::asm_sym, *op_sp, "sym operands for inline assembly are unstable", diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 3a7e0a70585f1..7cbfe143b4d83 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,8 +1,8 @@ use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; -use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind}; +use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; use rustc_hir as hir; use rustc_session::parse::feature_err; -use rustc_span::{sym, DesugaringKind}; +use rustc_span::sym; use smallvec::SmallVec; @@ -36,21 +36,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match s.kind { StmtKind::Local(ref local) => { let hir_id = self.lower_node_id(s.id); - match &local.kind { - LocalKind::InitElse(init, els) => { - let e = self.lower_let_else(hir_id, local, init, els, tail); - expr = Some(e); - // remaining statements are in let-else expression - break; - } - _ => { - let local = self.lower_local(local); - self.alias_attrs(hir_id, local.hir_id); - let kind = hir::StmtKind::Local(local); - let span = self.lower_span(s.span); - stmts.push(hir::Stmt { hir_id, kind, span }); - } - } + let local = self.lower_local(local); + self.alias_attrs(hir_id, local.hir_id); + let kind = hir::StmtKind::Local(local); + let span = self.lower_span(s.span); + stmts.push(hir::Stmt { hir_id, kind, span }); } StmtKind::Item(ref it) => { stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map( @@ -101,10 +91,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); + let els = if let LocalKind::InitElse(_, els) = &l.kind { + if !self.tcx.features().let_else { + feature_err( + &self.tcx.sess.parse_sess, + sym::let_else, + l.span, + "`let...else` statements are unstable", + ) + .emit(); + } + Some(self.lower_block(els, false)) + } else { + None + }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; self.lower_attrs(hir_id, &l.attrs); - self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source }) + self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source }) } fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { @@ -115,59 +119,4 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - - fn lower_let_else( - &mut self, - stmt_hir_id: hir::HirId, - local: &Local, - init: &Expr, - els: &Block, - tail: &[Stmt], - ) -> &'hir hir::Expr<'hir> { - let ty = local - .ty - .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); - let span = self.lower_span(local.span); - let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None); - let init = self.lower_expr(init); - let local_hir_id = self.lower_node_id(local.id); - self.lower_attrs(local_hir_id, &local.attrs); - let let_expr = { - let lex = self.arena.alloc(hir::Let { - hir_id: local_hir_id, - pat: self.lower_pat(&local.pat), - ty, - init, - span, - }); - self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new())) - }; - let then_expr = { - let (stmts, expr) = self.lower_stmts(tail); - let block = self.block_all(span, stmts, expr); - self.arena.alloc(self.expr_block(block, AttrVec::new())) - }; - let else_expr = { - let block = self.lower_block(els, false); - self.arena.alloc(self.expr_block(block, AttrVec::new())) - }; - self.alias_attrs(let_expr.hir_id, local_hir_id); - self.alias_attrs(else_expr.hir_id, local_hir_id); - let if_expr = self.arena.alloc(hir::Expr { - hir_id: stmt_hir_id, - span, - kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)), - }); - if !self.sess.features_untracked().let_else { - feature_err( - &self.sess.parse_sess, - sym::let_else, - local.span, - "`let...else` statements are unstable", - ) - .emit(); - } - if_expr - } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3babe73030a45..983efa48a4579 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -46,7 +46,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(e.id); return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; } else { - self.sess + self.tcx.sess .struct_span_err( e.span, "#[rustc_box] requires precisely one argument \ @@ -155,6 +155,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_await(span, expr) } ExprKind::Closure( + ref binder, capture_clause, asyncness, movability, @@ -164,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) => { if let Async::Yes { closure_id, .. } = asyncness { self.lower_expr_async_closure( + binder, capture_clause, e.id, closure_id, @@ -173,6 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } else { self.lower_expr_closure( + binder, capture_clause, e.id, movability, @@ -207,8 +210,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) } ExprKind::Underscore => { - self.sess - .struct_span_err( + self.tcx + .sess.struct_span_err( e.span, "in expressions, `_` can only be used on the left-hand side of an assignment", ) @@ -245,7 +248,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let rest = match &se.rest { StructRest::Base(e) => Some(self.lower_expr(e)), StructRest::Rest(sp) => { - self.sess + self.tcx + .sess .struct_span_err(*sp, "base expression required after `..`") .span_label(*sp, "add a base expression here") .emit(); @@ -474,7 +478,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { let try_span = this.mark_span_with_reason( DesugaringKind::TryBlock, - this.sess.source_map().end_point(body.span), + this.tcx.sess.source_map().end_point(body.span), this.allow_try_trait.clone(), ); @@ -604,13 +608,18 @@ impl<'hir> LoweringContext<'_, 'hir> { }); // `static |_task_context| -> <ret_ty> { body }`: - let generator_kind = hir::ExprKind::Closure { - capture_clause, - bound_generic_params: &[], - fn_decl, - body, - fn_decl_span: self.lower_span(span), - movability: Some(hir::Movability::Static), + let generator_kind = { + let c = self.arena.alloc(hir::Closure { + binder: hir::ClosureBinder::Default, + capture_clause, + bound_generic_params: &[], + fn_decl, + body, + fn_decl_span: self.lower_span(span), + movability: Some(hir::Movability::Static), + }); + + hir::ExprKind::Closure(c) }; let generator = hir::Expr { hir_id: self.lower_node_id(closure_node_id), @@ -653,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(hir::GeneratorKind::Async(_)) => {} Some(hir::GeneratorKind::Gen) | None => { let mut err = struct_span_err!( - self.sess, + self.tcx.sess, dot_await_span, E0728, "`await` is only allowed inside `async` functions and blocks" @@ -830,6 +839,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_closure( &mut self, + binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, movability: Movability, @@ -837,7 +847,9 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, ) -> hir::ExprKind<'hir> { - let (body, generator_option) = self.with_new_scopes(move |this| { + let (binder_clause, generic_params) = self.lower_closure_binder(binder); + + let (body_id, generator_option) = self.with_new_scopes(move |this| { let prev = this.current_item; this.current_item = Some(fn_decl_span); let mut generator_kind = None; @@ -852,18 +864,21 @@ impl<'hir> LoweringContext<'_, 'hir> { (body_id, generator_option) }); - self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| { + self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| { // Lower outside new scope to preserve `is_in_loop_condition`. let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None); - hir::ExprKind::Closure { + let c = self.arena.alloc(hir::Closure { + binder: binder_clause, capture_clause, bound_generic_params, fn_decl, - body, + body: body_id, fn_decl_span: this.lower_span(fn_decl_span), movability: generator_option, - } + }); + + hir::ExprKind::Closure(c) }) } @@ -878,7 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(hir::GeneratorKind::Gen) => { if decl.inputs.len() > 1 { struct_span_err!( - self.sess, + self.tcx.sess, fn_decl_span, E0628, "too many parameters for a generator (expected 0 or 1 parameters)" @@ -892,16 +907,37 @@ impl<'hir> LoweringContext<'_, 'hir> { } None => { if movability == Movability::Static { - struct_span_err!(self.sess, fn_decl_span, E0697, "closures cannot be static") - .emit(); + struct_span_err!( + self.tcx.sess, + fn_decl_span, + E0697, + "closures cannot be static" + ) + .emit(); } None } } } + fn lower_closure_binder<'c>( + &mut self, + binder: &'c ClosureBinder, + ) -> (hir::ClosureBinder, &'c [GenericParam]) { + let (binder, params) = match binder { + ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]), + &ClosureBinder::For { span, ref generic_params } => { + let span = self.lower_span(span); + (hir::ClosureBinder::For { span }, &**generic_params) + } + }; + + (binder, params) + } + fn lower_expr_async_closure( &mut self, + binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, inner_closure_id: NodeId, @@ -909,6 +945,15 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, ) -> hir::ExprKind<'hir> { + if let &ClosureBinder::For { span, .. } = binder { + self.tcx.sess.span_err( + span, + "`for<...>` binders on `async` closures are not currently supported", + ); + } + + let (binder_clause, generic_params) = self.lower_closure_binder(binder); + let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; @@ -916,7 +961,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(cramertj): allow `async` non-`move` closures with arguments. if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { struct_span_err!( - this.sess, + this.tcx.sess, fn_decl_span, E0708, "`async` non-`move` closures with parameters are not currently supported", @@ -946,20 +991,22 @@ impl<'hir> LoweringContext<'_, 'hir> { body_id }); - self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| { + self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| { // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); - hir::ExprKind::Closure { + let c = self.arena.alloc(hir::Closure { + binder: binder_clause, capture_clause, bound_generic_params, fn_decl, body, fn_decl_span: this.lower_span(fn_decl_span), movability: None, - } + }); + hir::ExprKind::Closure(c) }) } @@ -1163,7 +1210,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let fields_omitted = match &se.rest { StructRest::Base(e) => { - self.sess + self.tcx + .sess .struct_span_err( e.span, "functional record updates are not allowed in destructuring \ @@ -1371,7 +1419,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(hir::GeneratorKind::Gen) => {} Some(hir::GeneratorKind::Async(_)) => { struct_span_err!( - self.sess, + self.tcx.sess, span, E0727, "`async` generators are not yet supported" @@ -1516,7 +1564,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, self.allow_try_trait.clone(), ); - let try_span = self.sess.source_map().end_point(span); + let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, try_span, diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 4be22020ba153..ddd54f7c2089d 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -192,9 +192,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_pat(&mut self, pat: &'hir Pat<'hir>) { - let node = - if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) }; - self.insert(pat.span, pat.hir_id, node); + self.insert(pat.span, pat.hir_id, Node::Pat(pat)); self.with_parent(pat.hir_id, |this| { intravisit::walk_pat(this, pat); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 0ef213716945c..7da49143b461e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,7 +1,6 @@ use super::ResolverAstLoweringExt; use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; -use super::{LoweringContext, ParamMode}; -use crate::{Arena, FnDeclKind}; +use super::{FnDeclKind, LoweringContext, ParamMode}; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; @@ -12,12 +11,9 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; -use rustc_hir::definitions::Definitions; use rustc_hir::PredicateOrigin; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::ty::{ResolverAstLowering, ResolverOutputs}; -use rustc_session::cstore::CrateStoreDyn; -use rustc_session::Session; +use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -27,12 +23,8 @@ use smallvec::{smallvec, SmallVec}; use std::iter; pub(super) struct ItemLowerer<'a, 'hir> { - pub(super) sess: &'a Session, - pub(super) definitions: &'a mut Definitions, - pub(super) cstore: &'a CrateStoreDyn, - pub(super) resolutions: &'a ResolverOutputs, + pub(super) tcx: TyCtxt<'hir>, pub(super) resolver: &'a mut ResolverAstLowering, - pub(super) arena: &'hir Arena<'hir>, pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>, pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>, } @@ -65,12 +57,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { ) { let mut lctx = LoweringContext { // Pseudo-globals. - sess: &self.sess, - definitions: self.definitions, - cstore: self.cstore, - resolutions: self.resolutions, + tcx: self.tcx, resolver: self.resolver, - arena: self.arena, + arena: self.tcx.hir_arena, // HirId handling. bodies: Vec::new(), @@ -144,12 +133,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { let def_id = self.resolver.node_id_to_def_id[&item.id]; - let parent_id = { - let parent = self.definitions.def_key(def_id).parent; - let local_def_index = parent.unwrap(); - LocalDefId { local_def_index } - }; - + let parent_id = self.tcx.local_parent(def_id); let parent_hir = self.lower_node(parent_id).unwrap(); self.with_lctx(item.id, |lctx| { // Evaluate with the lifetimes in `params` in-scope. @@ -1272,13 +1256,13 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi { match ext { Extern::None => abi::Abi::Rust, - Extern::Implicit => abi::Abi::FALLBACK, - Extern::Explicit(abi) => self.lower_abi(abi), + Extern::Implicit(_) => abi::Abi::FALLBACK, + Extern::Explicit(abi, _) => self.lower_abi(abi), } } fn error_on_invalid_abi(&self, abi: StrLit) { - struct_span_err!(self.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol) + struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol) .span_label(abi.span, "invalid ABI") .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) .emit(); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e8b92eaad5c8d..7cd360623ec42 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -31,7 +31,7 @@ //! in the HIR, especially for multiple identifiers. #![feature(box_patterns)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] @@ -49,18 +49,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, Handler}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; -use rustc_hir::definitions::{DefPathData, Definitions}; +use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::ty::{ResolverAstLowering, ResolverOutputs}; -use rustc_query_system::ich::StableHashingContext; -use rustc_session::cstore::CrateStoreDyn; +use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::feature_err; -use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -83,19 +80,12 @@ mod item; mod pat; mod path; -rustc_hir::arena_types!(rustc_arena::declare_arena); - -struct LoweringContext<'a, 'hir: 'a> { - /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. - sess: &'a Session, - - definitions: &'a mut Definitions, - cstore: &'a CrateStoreDyn, - resolutions: &'a ResolverOutputs, +struct LoweringContext<'a, 'hir> { + tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering, /// Used to allocate HIR nodes. - arena: &'hir Arena<'hir>, + arena: &'hir hir::Arena<'hir>, /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, @@ -391,61 +381,58 @@ fn index_crate<'a>( /// Compute the hash for the HIR of the full crate. /// This hash will then be part of the crate_hash which is stored in the metadata. fn compute_hir_hash( - sess: &Session, - definitions: &Definitions, - cstore: &CrateStoreDyn, - resolver: &ResolverOutputs, + tcx: TyCtxt<'_>, owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>, ) -> Fingerprint { let mut hir_body_nodes: Vec<_> = owners .iter_enumerated() .filter_map(|(def_id, info)| { let info = info.as_owner()?; - let def_path_hash = definitions.def_path_hash(def_id); + let def_path_hash = tcx.hir().def_path_hash(def_id); Some((def_path_hash, info)) }) .collect(); hir_body_nodes.sort_unstable_by_key(|bn| bn.0); - let mut stable_hasher = StableHasher::new(); - let mut hcx = StableHashingContext::new(sess, definitions, cstore, &resolver.source_span); - hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher); - stable_hasher.finish() + tcx.with_stable_hashing_context(|mut hcx| { + let mut stable_hasher = StableHasher::new(); + hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() + }) } -pub fn lower_crate<'hir>( - sess: &Session, - krate: &Crate, - definitions: &mut Definitions, - cstore: &CrateStoreDyn, - resolutions: &ResolverOutputs, - mut resolver: ResolverAstLowering, - arena: &'hir Arena<'hir>, -) -> &'hir hir::Crate<'hir> { - let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); - - let ast_index = index_crate(&resolver.node_id_to_def_id, krate); +pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> { + let sess = tcx.sess; + let krate = tcx.untracked_crate.steal(); + let mut resolver = tcx.resolver_for_lowering(()).steal(); - let mut owners = - IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, definitions.def_index_count()); + let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); + let mut owners = IndexVec::from_fn_n( + |_| hir::MaybeOwner::Phantom, + tcx.definitions_untracked().def_index_count(), + ); for def_id in ast_index.indices() { item::ItemLowerer { - sess, - definitions, - cstore, - resolutions, + tcx, resolver: &mut resolver, - arena, ast_index: &ast_index, owners: &mut owners, } .lower_node(def_id); } - let hir_hash = compute_hir_hash(sess, definitions, cstore, resolutions, &owners); - let krate = hir::Crate { owners, hir_hash }; - arena.alloc(krate) + // Drop AST to free memory + std::mem::drop(ast_index); + sess.time("drop_ast", || std::mem::drop(krate)); + + // Discard hygiene data, which isn't required after lowering to HIR. + if !sess.opts.unstable_opts.keep_hygiene_data { + rustc_span::hygiene::clear_syntax_context_map(); + } + + let hir_hash = compute_hir_hash(tcx, &owners); + hir::Crate { owners, hir_hash } } #[derive(Copy, Clone, PartialEq, Debug)] @@ -464,38 +451,25 @@ enum ParenthesizedGenericArgs { } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { - StableHashingContext::new( - self.sess, - self.definitions, - self.cstore, - &self.resolutions.source_span, - ) - } - fn create_def( &mut self, parent: LocalDefId, node_id: ast::NodeId, data: DefPathData, ) -> LocalDefId { + debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( self.opt_local_def_id(node_id).is_none(), "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", node_id, data, - self.definitions.def_key(self.local_def_id(node_id)), + self.tcx.hir().def_key(self.local_def_id(node_id)), ); - let def_id = self.definitions.create_def(parent, data); + let def_id = self.tcx.create_def(parent, data); - // Some things for which we allocate `LocalDefId`s don't correspond to - // anything in the AST, so they don't have a `NodeId`. For these cases - // we don't need a mapping from `NodeId` to `LocalDefId`. - if node_id != ast::DUMMY_NODE_ID { - debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); - self.resolver.node_id_to_def_id.insert(node_id, def_id); - } + debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); + self.resolver.node_id_to_def_id.insert(node_id, def_id); def_id } @@ -515,6 +489,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) } + /// Freshen the `LoweringContext` and ready it to lower a nested item. + /// The lowered item is registered into `self.children`. + /// + /// This function sets up `HirId` lowering infrastructure, + /// and stashes the shared mutable state to avoid pollution by the closure. #[instrument(level = "debug", skip(self, f))] fn with_hir_id_owner( &mut self, @@ -533,8 +512,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); - // Do not reset `next_node_id` and `node_id_to_def_id` as we want to refer to the - // subdefinitions' nodes. + + // Do not reset `next_node_id` and `node_id_to_def_id`: + // we want `f` to be able to refer to the `LocalDefId`s that the caller created. + // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s. // Always allocate the first `HirId` for the owner itself. let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0)); @@ -578,7 +559,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bodies.sort_by_key(|(k, _)| *k); let bodies = SortedMap::from_presorted_elements(bodies); let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); - let (nodes, parenting) = index::index_hir(self.sess, self.definitions, node, &bodies); + let (nodes, parenting) = + index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, @@ -587,10 +569,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { local_id_to_def_id, }; let attrs = { - let mut hcx = self.create_stable_hashing_context(); - let mut stable_hasher = StableHasher::new(); - attrs.hash_stable(&mut hcx, &mut stable_hasher); - let hash = stable_hasher.finish(); + let hash = self.tcx.with_stable_hashing_context(|mut hcx| { + let mut stable_hasher = StableHasher::new(); + attrs.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() + }); hir::AttributeMap { map: attrs, hash } }; @@ -604,18 +587,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { node: hir::OwnerNode<'hir>, bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>, ) -> (Fingerprint, Fingerprint) { - let mut hcx = self.create_stable_hashing_context(); - let mut stable_hasher = StableHasher::new(); - hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| { - node.hash_stable(hcx, &mut stable_hasher) - }); - let hash_including_bodies = stable_hasher.finish(); - let mut stable_hasher = StableHasher::new(); - hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| { - node.hash_stable(hcx, &mut stable_hasher) - }); - let hash_without_bodies = stable_hasher.finish(); - (hash_including_bodies, hash_without_bodies) + self.tcx.with_stable_hashing_context(|mut hcx| { + let mut stable_hasher = StableHasher::new(); + hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| { + node.hash_stable(hcx, &mut stable_hasher) + }); + let hash_including_bodies = stable_hasher.finish(); + let mut stable_hasher = StableHasher::new(); + hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| { + node.hash_stable(hcx, &mut stable_hasher) + }); + let hash_without_bodies = stable_hasher.finish(); + (hash_including_bodies, hash_without_bodies) + }) } /// This method allocates a new `HirId` for the given `NodeId` and stores it in @@ -656,9 +640,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + /// Generate a new `HirId` without a backing `NodeId`. fn next_id(&mut self) -> hir::HirId { - let node_id = self.next_node_id(); - self.lower_node_id(node_id) + let owner = self.current_hir_id_owner; + let local_id = self.item_local_id_counter; + assert_ne!(local_id, hir::ItemLocalId::new(0)); + self.item_local_id_counter.increment_by(1); + hir::HirId { owner, local_id } } #[instrument(level = "trace", skip(self))] @@ -691,8 +679,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_import_res(id).present_items() } - fn diagnostic(&self) -> &rustc_errors::Handler { - self.sess.diagnostic() + fn diagnostic(&self) -> &Handler { + self.tcx.sess.diagnostic() } /// Reuses the span but adds information like the kind of the desugaring and features that are @@ -703,18 +691,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, allow_internal_unstable: Option<Lrc<[Symbol]>>, ) -> Span { - span.mark_with_reason( - allow_internal_unstable, - reason, - self.sess.edition(), - self.create_stable_hashing_context(), - ) + self.tcx.with_stable_hashing_context(|hcx| { + span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx) + }) } /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - if self.sess.opts.debugging_opts.incremental_relative_spans { + if self.tcx.sess.opts.unstable_opts.incremental_relative_spans { span.with_parent(Some(self.current_hir_id_owner)) } else { // Do not make spans relative when not using incremental compilation. @@ -1061,7 +1046,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) { - let mut err = self.sess.struct_span_err( + let mut err = self.tcx.sess.struct_span_err( data.span, "parenthesized generic arguments cannot be used in associated type constraints", ); @@ -1106,7 +1091,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), ast::GenericArg::Type(ty) => { match ty.kind { - TyKind::Infer if self.sess.features_untracked().generic_arg_infer => { + TyKind::Infer if self.tcx.features().generic_arg_infer => { return GenericArg::Infer(hir::InferArg { hir_id: self.lower_node_id(ty.id), span: self.lower_span(ty.span), @@ -1174,6 +1159,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, itctx: ImplTraitContext, ) -> hir::Ty<'hir> { + // Check whether we should interpret this as a bare trait object. + // This check mirrors the one in late resolution. We only introduce this special case in + // the rare occurence we need to lower `Fresh` anonymous lifetimes. + // The other cases when a qpath should be opportunistically made a trait object are handled + // by `ty_path`. + if qself.is_none() + && let Some(partial_res) = self.resolver.get_partial_res(t.id) + && partial_res.unresolved_segments() == 0 + && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() + { + let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { + let bound = this.lower_poly_trait_ref( + &PolyTraitRef { + bound_generic_params: vec![], + trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, + span: t.span + }, + itctx, + ); + let bounds = this.arena.alloc_from_iter([bound]); + let lifetime_bound = this.elided_dyn_bound(t.span); + (bounds, lifetime_bound) + }); + let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None); + return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() }; + } + let id = self.lower_node_id(t.id); let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx); self.ty_path(id, t.span, qpath) @@ -1203,7 +1215,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { self.next_node_id() }; - let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); + let span = self.tcx.sess.source_map().next_point(t.span.shrink_to_lo()); Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } }); let lifetime = self.lower_lifetime(®ion); @@ -1307,7 +1319,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } ImplTraitContext::Disallowed(position) => { let mut err = struct_span_err!( - self.sess, + self.tcx.sess, t.span, E0562, "`impl Trait` only allowed in function and inherent method return types, not in {}", @@ -1320,7 +1332,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), TyKind::CVarArgs => { - self.sess.delay_span_bug( + self.tcx.sess.delay_span_bug( t.span, "`TyKind::CVarArgs` should have been handled elsewhere", ); @@ -1925,7 +1937,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir_id, name, span: self.lower_span(param.span()), - pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle), + pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), } @@ -2067,11 +2079,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen { match c.value.kind { ExprKind::Underscore => { - if self.sess.features_untracked().generic_arg_infer { + if self.tcx.features().generic_arg_infer { hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span) } else { feature_err( - &self.sess.parse_sess, + &self.tcx.sess.parse_sess, sym::generic_arg_infer, c.value.span, "using `_` for array lengths is unstable", @@ -2134,7 +2146,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug_assert!(!a.is_empty()); self.attrs.insert(hir_id.local_id, a); } - let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None }; + let local = hir::Local { + hir_id, + init, + pat, + els: None, + source, + span: self.lower_span(span), + ty: None, + }; self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 52ba5daf01410..393be3b454c37 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -133,7 +133,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We should've returned in the for loop above. - self.sess.diagnostic().span_bug( + self.diagnostic().span_bug( p.span, &format!( "lower_qpath: no final extension segment in {}..{}", @@ -193,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Err => { - let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); + let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg); err.span_label(data.span, "only `Fn` traits may use parentheses"); // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` if !data.inputs.is_empty() { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 503bdbad25828..334326e927fad 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,7 +13,9 @@ use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; +use rustc_errors::{ + error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, +}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -117,33 +119,23 @@ impl<'a> AstValidator<'a> { /// Emits an error banning the `let` expression provided in the given location. fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) { - let sess = &self.session; - if sess.opts.unstable_features.is_nightly_build() { - let err = "`let` expressions are not supported here"; - let mut diag = sess.struct_span_err(expr.span, err); - diag.note("only supported directly in conditions of `if` and `while` expressions"); - match forbidden_let_reason { - ForbiddenLetReason::GenericForbidden => {} - ForbiddenLetReason::NotSupportedOr(span) => { - diag.span_note( - span, - "`||` operators are not supported in let chain expressions", - ); - } - ForbiddenLetReason::NotSupportedParentheses(span) => { - diag.span_note( - span, - "`let`s wrapped in parentheses are not supported in a context with let \ - chains", - ); - } + let err = "`let` expressions are not supported here"; + let mut diag = self.session.struct_span_err(expr.span, err); + diag.note("only supported directly in conditions of `if` and `while` expressions"); + match forbidden_let_reason { + ForbiddenLetReason::GenericForbidden => {} + ForbiddenLetReason::NotSupportedOr(span) => { + diag.span_note(span, "`||` operators are not supported in let chain expressions"); + } + ForbiddenLetReason::NotSupportedParentheses(span) => { + diag.span_note( + span, + "`let`s wrapped in parentheses are not supported in a context with let \ + chains", + ); } - diag.emit(); - } else { - sess.struct_span_err(expr.span, "expected expression, found statement (`let`)") - .note("variable declaration using `let` is a statement") - .emit(); } + diag.emit(); } fn check_gat_where( @@ -476,6 +468,17 @@ impl<'a> AstValidator<'a> { } fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { + self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ()); + } + + fn error_item_without_body_with_help( + &self, + sp: Span, + ctx: &str, + msg: &str, + sugg: &str, + help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>), + ) { let source_map = self.session.source_map(); let end = source_map.end_point(sp); let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { @@ -483,15 +486,15 @@ impl<'a> AstValidator<'a> { } else { sp.shrink_to_hi() }; - self.err_handler() - .struct_span_err(sp, msg) - .span_suggestion( - replace_span, - &format!("provide a definition for the {}", ctx), - sugg, - Applicability::HasPlaceholders, - ) - .emit(); + let mut err = self.err_handler().struct_span_err(sp, msg); + err.span_suggestion( + replace_span, + &format!("provide a definition for the {}", ctx), + sugg, + Applicability::HasPlaceholders, + ); + help(&mut err); + err.emit(); } fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) { @@ -630,7 +633,8 @@ impl<'a> AstValidator<'a> { match (fk.ctxt(), fk.header()) { (Some(FnCtxt::Foreign), _) => return, (Some(FnCtxt::Free), Some(header)) => match header.ext { - Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit + Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) + | Extern::Implicit(_) if matches!(header.unsafety, Unsafe::Yes(_)) => { return; @@ -842,7 +846,7 @@ impl<'a> AstValidator<'a> { .emit(); }); self.check_late_bound_lifetime_defs(&bfty.generic_params); - if let Extern::Implicit = bfty.ext { + if let Extern::Implicit(_) = bfty.ext { let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo()); self.maybe_lint_missing_abi(sig_span, ty.id); } @@ -1190,8 +1194,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if body.is_none() { let msg = "free function without a body"; - self.error_item_without_body(item.span, "function", msg, " { <body> }"); + let ext = sig.header.ext; + + let f = |e: &mut DiagnosticBuilder<'_, _>| { + if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext + { + let start_suggestion = if let Extern::Explicit(abi, _) = ext { + format!("extern \"{}\" {{", abi.symbol_unescaped) + } else { + "extern {".to_owned() + }; + + let end_suggestion = " }".to_owned(); + let end_span = item.span.shrink_to_hi(); + + e + .multipart_suggestion( + "if you meant to declare an externally defined function, use an `extern` block", + vec![(*start_span, start_suggestion), (end_span, end_suggestion)], + Applicability::MaybeIncorrect, + ); + } + }; + + self.error_item_without_body_with_help( + item.span, + "function", + msg, + " { <body> }", + f, + ); } + self.visit_vis(&item.vis); self.visit_ident(item.ident); let kind = @@ -1553,10 +1587,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } + if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk { + self.check_late_bound_lifetime_defs(generic_params); + } + if let FnKind::Fn( _, _, - FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. }, + FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. }, _, _, _, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 37c4f665415fc..ad0e0384acffa 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -283,7 +283,7 @@ impl<'a> PostExpansionVisitor<'a> { } fn check_extern(&self, ext: ast::Extern, constness: ast::Const) { - if let ast::Extern::Explicit(abi) = ext { + if let ast::Extern::Explicit(abi, _) = ext { self.check_abi(abi, constness); } } @@ -738,12 +738,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { "`if let` guards are experimental", "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`" ); - gate_all!(let_chains, "`let` expressions in this position are unstable"); gate_all!( async_closure, "async closures are unstable", "to use an async block, remove the `||`: `async {`" ); + gate_all!( + closure_lifetime_binder, + "`for<...>` binders for closures are experimental", + "consider removing `for<...>`" + ); gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); gate_all!(generators, "yield syntax is experimental"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 9d52c32885db0..2e3ac0c60186d 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -8,7 +8,7 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_is_partitioned)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index ad8dbfd506d21..c9e3a7edfa67d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1734,10 +1734,10 @@ impl<'a> State<'a> { match header.ext { ast::Extern::None => {} - ast::Extern::Implicit => { + ast::Extern::Implicit(_) => { self.word_nbsp("extern"); } - ast::Extern::Explicit(abi) => { + ast::Extern::Explicit(abi, _) => { self.word_nbsp("extern"); self.print_literal(&abi.as_lit()); self.nbsp(); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9f44f1b6cc205..ead38caee287f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -389,6 +389,7 @@ impl<'a> State<'a> { self.bclose(expr.span, empty); } ast::ExprKind::Closure( + ref binder, capture_clause, asyncness, movability, @@ -396,6 +397,7 @@ impl<'a> State<'a> { ref body, _, ) => { + self.print_closure_binder(binder); self.print_movability(movability); self.print_asyncness(asyncness); self.print_capture_clause(capture_clause); @@ -594,6 +596,15 @@ impl<'a> State<'a> { self.end(); // Close enclosing cbox. } + fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) { + match binder { + ast::ClosureBinder::NotPresent => {} + ast::ClosureBinder::For { generic_params, .. } => { + self.print_formal_generic_params(&generic_params) + } + } + } + fn print_movability(&mut self, movability: ast::Movability) { match movability { ast::Movability::Static => self.word_space("static"), diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ce7c0eb72cd24..dcfbecedfe8ff 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -137,7 +137,7 @@ impl ConstStability { pub enum StabilityLevel { // Reason for the current stability level and the relevant rust-lang issue Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool }, - Stable { since: Symbol }, + Stable { since: Symbol, allowed_through_unstable_modules: bool }, } impl StabilityLevel { @@ -172,6 +172,7 @@ where let mut stab: Option<(Stability, Span)> = None; let mut const_stab: Option<(ConstStability, Span)> = None; let mut promotable = false; + let mut allowed_through_unstable_modules = false; let diagnostic = &sess.parse_sess.span_diagnostic; @@ -182,6 +183,7 @@ where sym::unstable, sym::stable, sym::rustc_promotable, + sym::rustc_allowed_through_unstable_modules, ] .iter() .any(|&s| attr.has_name(s)) @@ -193,6 +195,8 @@ where if attr.has_name(sym::rustc_promotable) { promotable = true; + } else if attr.has_name(sym::rustc_allowed_through_unstable_modules) { + allowed_through_unstable_modules = true; } // attributes with data else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta { @@ -406,7 +410,7 @@ where match (feature, since) { (Some(feature), Some(since)) => { - let level = Stable { since }; + let level = Stable { since, allowed_through_unstable_modules: false }; if sym::stable == meta_name { stab = Some((Stability { level, feature }, attr.span)); } else { @@ -447,6 +451,27 @@ where } } + if allowed_through_unstable_modules { + if let Some(( + Stability { + level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. }, + .. + }, + _, + )) = stab + { + *allowed_through_unstable_modules = true; + } else { + struct_span_err!( + diagnostic, + item_sp, + E0789, + "`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute" + ) + .emit(); + } + } + (stab, const_stab) } @@ -856,7 +881,6 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(u32), - ReprNoNiche, } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -904,7 +928,6 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { sym::packed => Some(ReprPacked(1)), sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), - sym::no_niche => Some(ReprNoNiche), sym::align => { let mut err = struct_span_err!( diagnostic, @@ -943,7 +966,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message), }; - } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) + } else if matches!(name, sym::C | sym::simd | sym::transparent) || int_type_of_word(name).is_some() { recognised = true; @@ -1001,7 +1024,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { } else { if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche + sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; @@ -1039,7 +1062,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { .emit(); } else if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche + sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index c3f9f0cf3621f..afe1d191d10e1 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,7 +4,7 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #[macro_use] diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 0b531623ba6f5..fbf628e865e2c 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -11,7 +11,7 @@ either = "1.5.0" itertools = "0.10.1" tracing = "0.1" polonius-engine = "0.13.0" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_graphviz = { path = "../rustc_graphviz" } @@ -19,6 +19,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index c7d0e3361331c..41279588e6334 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -92,9 +92,9 @@ impl LocalsStateAtExit { struct HasStorageDead(BitSet<Local>); impl<'tcx> Visitor<'tcx> for HasStorageDead { - fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { + fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) { if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) { - self.0.insert(*local); + self.0.insert(local); } } } @@ -223,7 +223,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { self.super_assign(assigned_place, rvalue, location) } - fn visit_local(&mut self, temp: &Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location) { if !context.is_use() { return; } @@ -232,7 +232,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> { // check whether we (earlier) saw a 2-phase borrow like // // TMP = &mut place - if let Some(&borrow_index) = self.pending_activations.get(temp) { + if let Some(&borrow_index) = self.pending_activations.get(&temp) { let borrow_data = &mut self.location_map[borrow_index.as_usize()]; // Watch out: the use of TMP in the borrow itself diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index a1233d62cb02e..08ea00d71ef9d 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,4 +1,6 @@ -use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan, +}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -31,22 +33,6 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - pub(crate) fn cannot_act_on_uninitialized_variable( - &self, - span: Span, - verb: &str, - desc: &str, - ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { - struct_span_err!( - self, - span, - E0381, - "{} of possibly-uninitialized variable: `{}`", - verb, - desc, - ) - } - pub(crate) fn cannot_mutably_borrow_multiply( &self, new_loan_span: Span, @@ -173,8 +159,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { self, new_loan_span, E0501, - "cannot borrow {}{} as {} because previous closure \ - requires unique access", + "cannot borrow {}{} as {} because previous closure requires unique access", desc_new, opt_via, kind_new, @@ -451,9 +436,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { self, closure_span, E0373, - "{} may outlive the current function, \ - but it borrows {}, \ - which is owned by the current function", + "{} may outlive the current function, but it borrows {}, which is owned by the current \ + function", closure_kind, borrowed_path, ); @@ -476,10 +460,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",) } - fn struct_span_err_with_code<S: Into<MultiSpan>>( + #[rustc_lint_diagnostics] + pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, - msg: &str, + msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code) diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index e4ffae38c33a5..5e9cec5c350c9 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -5,8 +5,8 @@ use rustc_middle::mir::{ BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, RegionVid, Ty}; use crate::{ @@ -149,7 +149,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { fn visit_ascribe_user_ty( &mut self, _place: &Place<'tcx>, - _variance: &ty::Variance, + _variance: ty::Variance, _user_ty: &UserTypeProjection, _location: Location, ) { @@ -163,7 +163,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { /// `location`. fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location) where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location); diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 07f182102f346..1ef2b0ae98843 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -19,6 +19,9 @@ use std::fmt; use std::rc::Rc; use crate::region_infer::values::RegionElement; +use crate::session_diagnostics::HigherRankedErrorCause; +use crate::session_diagnostics::HigherRankedLifetimeError; +use crate::session_diagnostics::HigherRankedSubtypeError; use crate::MirBorrowckCtxt; #[derive(Clone)] @@ -69,7 +72,7 @@ impl<'tcx> UniverseInfo<'tcx> { // up in the existing UI tests. Consider investigating this // some more. mbcx.buffer_error( - mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"), + mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }), ); } } @@ -216,9 +219,12 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { tcx: TyCtxt<'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); - err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate)); - err + tcx.sess.create_err(HigherRankedLifetimeError { + cause: Some(HigherRankedErrorCause::CouldNotProve { + predicate: self.canonical_query.value.value.predicate.to_string(), + }), + span, + }) } fn base_universe(&self) -> ty::UniverseIndex { @@ -263,9 +269,12 @@ where tcx: TyCtxt<'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); - err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value)); - err + tcx.sess.create_err(HigherRankedLifetimeError { + cause: Some(HigherRankedErrorCause::CouldNotNormalize { + value: self.canonical_query.value.value.value.to_string(), + }), + span, + }) } fn base_universe(&self) -> ty::UniverseIndex { @@ -326,7 +335,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // and is only the fallback when the nice error fails. Consider improving this some more. - tcx.sess.struct_span_err(span, "higher-ranked lifetime error") + tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span }) } fn base_universe(&self) -> ty::UniverseIndex { @@ -366,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // and is only the fallback when the nice error fails. Consider improving this some more. - tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!") + tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span }) } fn base_universe(&self) -> ty::UniverseIndex { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 73c0bf16a1f99..ee96dbc2f60b4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2,9 +2,12 @@ use either::Either; use rustc_const_eval::util::CallKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; @@ -18,8 +21,9 @@ use rustc_middle::ty::{ self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty, }; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; +use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::sym; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::TraitEngineExt as _; @@ -94,32 +98,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; } - let item_msg = - match self.describe_place_with_options(used_place, IncludingDowncast(true)) { - Some(name) => format!("`{}`", name), - None => "value".to_owned(), - }; - let mut err = self.cannot_act_on_uninitialized_variable( + let err = self.report_use_of_uninitialized( + mpi, + used_place, + moved_place, + desired_action, span, - desired_action.as_noun(), - &self - .describe_place_with_options(moved_place, IncludingDowncast(true)) - .unwrap_or_else(|| "_".to_owned()), + use_spans, ); - err.span_label(span, format!("use of possibly-uninitialized {}", item_msg)); - - use_spans.var_span_label_path_only( - &mut err, - format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), - ); - self.buffer_error(err); } else { if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) { if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) { debug!( - "report_use_of_moved_or_uninitialized place: error suppressed \ - mois={:?}", + "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}", move_out_indices ); return; @@ -317,7 +309,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { )); // Check first whether the source is accessible (issue #87060) - if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) { err.span_note(deref_target, "deref defined here"); } } @@ -326,6 +318,130 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + fn report_use_of_uninitialized( + &self, + mpi: MovePathIndex, + used_place: PlaceRef<'tcx>, + moved_place: PlaceRef<'tcx>, + desired_action: InitializationRequiringAction, + span: Span, + use_spans: UseSpans<'tcx>, + ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { + // We need all statements in the body where the binding was assigned to to later find all + // the branching code paths where the binding *wasn't* assigned to. + let inits = &self.move_data.init_path_map[mpi]; + let move_path = &self.move_data.move_paths[mpi]; + let decl_span = self.body.local_decls[move_path.place.local].source_info.span; + let mut spans = vec![]; + for init_idx in inits { + let init = &self.move_data.inits[*init_idx]; + let span = init.span(&self.body); + if !span.is_dummy() { + spans.push(span); + } + } + + let (name, desc) = + match self.describe_place_with_options(moved_place, IncludingDowncast(true)) { + Some(name) => (format!("`{name}`"), format!("`{name}` ")), + None => ("the variable".to_string(), String::new()), + }; + let path = match self.describe_place_with_options(used_place, IncludingDowncast(true)) { + Some(name) => format!("`{name}`"), + None => "value".to_string(), + }; + + // We use the statements were the binding was initialized, and inspect the HIR to look + // for the branching codepaths that aren't covered, to point at them. + let hir_id = self.mir_hir_id(); + let map = self.infcx.tcx.hir(); + let body_id = map.body_owned_by(hir_id); + let body = map.body(body_id); + + let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] }; + visitor.visit_body(&body); + + let isnt_initialized = if let InitializationRequiringAction::PartialAssignment + | InitializationRequiringAction::Assignment = desired_action + { + // The same error is emitted for bindings that are *sometimes* initialized and the ones + // that are *partially* initialized by assigning to a field of an uninitialized + // binding. We differentiate between them for more accurate wording here. + "isn't fully initialized" + } else if spans + .iter() + .filter(|i| { + // We filter these to avoid misleading wording in cases like the following, + // where `x` has an `init`, but it is in the same place we're looking at: + // ``` + // let x; + // x += 1; + // ``` + !i.contains(span) + // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs` + && !visitor + .errors + .iter() + .map(|(sp, _)| *sp) + .any(|sp| span < sp && !sp.contains(span)) + }) + .count() + == 0 + { + "isn't initialized" + } else { + "is possibly-uninitialized" + }; + + let used = desired_action.as_general_verb_in_past_tense(); + let mut err = + struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}"); + use_spans.var_span_label_path_only( + &mut err, + format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), + ); + + if let InitializationRequiringAction::PartialAssignment + | InitializationRequiringAction::Assignment = desired_action + { + err.help( + "partial initialization isn't supported, fully initialize the binding with a \ + default value and mutate it, or use `std::mem::MaybeUninit`", + ); + } + err.span_label(span, format!("{path} {used} here but it {isnt_initialized}")); + + let mut shown = false; + for (sp, label) in visitor.errors { + if sp < span && !sp.overlaps(span) { + // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention + // match arms coming after the primary span because they aren't relevant: + // ``` + // let x; + // match y { + // _ if { x = 2; true } => {} + // _ if { + // x; //~ ERROR + // false + // } => {} + // _ => {} // We don't want to point to this. + // }; + // ``` + err.span_label(sp, &label); + shown = true; + } + } + if !shown { + for sp in &spans { + if *sp < span && !sp.overlaps(span) { + err.span_label(*sp, "binding initialized here in some conditions"); + } + } + } + err.span_label(decl_span, "binding declared here but left uninitialized"); + err + } + fn suggest_borrow_fn_like( &self, err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, @@ -1111,8 +1227,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { from_closure: false, region_name: RegionName { - source: - RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name), + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), .. }, span, @@ -1384,7 +1499,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | BorrowExplanation::UsedLaterInLoop(..) | BorrowExplanation::UsedLaterWhenDropped { .. } => { // Only give this note and suggestion if it could be relevant. - err.note("consider using a `let` binding to create a longer lived value"); + let sm = self.infcx.tcx.sess.source_map(); + let mut suggested = false; + let msg = "consider using a `let` binding to create a longer lived value"; + + /// We check that there's a single level of block nesting to ensure always correct + /// suggestions. If we don't, then we only provide a free-form message to avoid + /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`. + /// We could expand the analysis to suggest hoising all of the relevant parts of + /// the users' code to make the code compile, but that could be too much. + struct NestedStatementVisitor { + span: Span, + current: usize, + found: usize, + } + + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { + fn visit_block(&mut self, block: &hir::Block<'tcx>) { + self.current += 1; + walk_block(self, block); + self.current -= 1; + } + fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + if self.span == expr.span { + self.found = self.current; + } + walk_expr(self, expr); + } + } + let source_info = self.body.source_info(location); + if let Some(scope) = self.body.source_scopes.get(source_info.scope) + && let ClearCrossCrate::Set(scope_data) = &scope.local_data + && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root) + && let Some(id) = node.body_id() + && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind + { + for stmt in block.stmts { + let mut visitor = NestedStatementVisitor { + span: proper_span, + current: 0, + found: 0, + }; + visitor.visit_stmt(stmt); + if visitor.found == 0 + && stmt.span.contains(proper_span) + && let Some(p) = sm.span_to_margin(stmt.span) + && let Ok(s) = sm.span_to_snippet(proper_span) + { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + suggested = true; + break; + } + } + } + if !suggested { + err.note(msg); + } } _ => {} } @@ -1482,21 +1660,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = tcx.erase_regions(return_ty); // to avoid panics - if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { - if self + if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) + && self .infcx .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env) .must_apply_modulo_regions() - { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { - err.span_suggestion_hidden( - return_span, - "use `.collect()` to allocate the iterator", - format!("{snippet}.collect::<Vec<_>>()"), - Applicability::MaybeIncorrect, - ); - } - } + { + err.span_suggestion_hidden( + return_span.shrink_to_hi(), + "use `.collect()` to allocate the iterator", + ".collect::<Vec<_>>()", + Applicability::MaybeIncorrect, + ); } } @@ -1586,7 +1761,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_span: Span, name: &Option<String>, upvar_span: Span, - upvar_name: &str, + upvar_name: Symbol, escape_span: Span, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { let tcx = self.infcx.tcx; @@ -1628,7 +1803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a { if location.statement_index == 0 { - let predecessors = body.predecessors()[location.block].to_vec(); + let predecessors = body.basic_blocks.predecessors()[location.block].to_vec(); Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) } else { Either::Right(std::iter::once(Location { @@ -1980,7 +2155,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } StorageDeadOrDrop::Destructor(_) => kind, }, - ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { + ProjectionElem::OpaqueCast { .. } + | ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) => { match place_ty.ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor @@ -2448,3 +2625,142 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { } } } + +/// Detect whether one of the provided spans is a statement nested within the top-most visited expr +struct ReferencedStatementsVisitor<'a>(&'a [Span], bool); + +impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> { + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { + match s.kind { + hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => { + self.1 = true; + } + _ => {} + } + } +} + +/// Given a set of spans representing statements initializing the relevant binding, visit all the +/// function expressions looking for branching code paths that *do not* initialize the binding. +struct ConditionVisitor<'b> { + spans: &'b [Span], + name: &'b str, + errors: Vec<(Span, String)>, +} + +impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + match ex.kind { + hir::ExprKind::If(cond, body, None) => { + // `if` expressions with no `else` that initialize the binding might be missing an + // `else` arm. + let mut v = ReferencedStatementsVisitor(self.spans, false); + v.visit_expr(body); + if v.1 { + self.errors.push(( + cond.span, + format!( + "if this `if` condition is `false`, {} is not initialized", + self.name, + ), + )); + self.errors.push(( + ex.span.shrink_to_hi(), + format!("an `else` arm might be missing here, initializing {}", self.name), + )); + } + } + hir::ExprKind::If(cond, body, Some(other)) => { + // `if` expressions where the binding is only initialized in one of the two arms + // might be missing a binding initialization. + let mut a = ReferencedStatementsVisitor(self.spans, false); + a.visit_expr(body); + let mut b = ReferencedStatementsVisitor(self.spans, false); + b.visit_expr(other); + match (a.1, b.1) { + (true, true) | (false, false) => {} + (true, false) => { + if other.span.is_desugaring(DesugaringKind::WhileLoop) { + self.errors.push(( + cond.span, + format!( + "if this condition isn't met and the `while` loop runs 0 \ + times, {} is not initialized", + self.name + ), + )); + } else { + self.errors.push(( + body.span.shrink_to_hi().until(other.span), + format!( + "if the `if` condition is `false` and this `else` arm is \ + executed, {} is not initialized", + self.name + ), + )); + } + } + (false, true) => { + self.errors.push(( + cond.span, + format!( + "if this condition is `true`, {} is not initialized", + self.name + ), + )); + } + } + } + hir::ExprKind::Match(e, arms, loop_desugar) => { + // If the binding is initialized in one of the match arms, then the other match + // arms might be missing an initialization. + let results: Vec<bool> = arms + .iter() + .map(|arm| { + let mut v = ReferencedStatementsVisitor(self.spans, false); + v.visit_arm(arm); + v.1 + }) + .collect(); + if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { + for (arm, seen) in arms.iter().zip(results) { + if !seen { + if loop_desugar == hir::MatchSource::ForLoopDesugar { + self.errors.push(( + e.span, + format!( + "if the `for` loop runs 0 times, {} is not initialized ", + self.name + ), + )); + } else if let Some(guard) = &arm.guard { + self.errors.push(( + arm.pat.span.to(guard.body().span), + format!( + "if this pattern and condition are matched, {} is not \ + initialized", + self.name + ), + )); + } else { + self.errors.push(( + arm.pat.span, + format!( + "if this pattern is matched, {} is not initialized", + self.name + ), + )); + } + } + } + } + } + // FIXME: should we also account for binops, particularly `&&` and `||`? `try` should + // also be accounted for. For now it is fine, as if we don't find *any* relevant + // branching code paths, we point at the places where the binding *is* initialized for + // *some* context. + _ => {} + } + walk_expr(self, ex); + } +} diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 230ccf5199066..72aee0267ac1e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; use crate::region_infer::BlameConstraint; @@ -282,7 +282,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ) { if let ConstraintCategory::OpaqueType = category { let suggestable_name = - if region_name.was_named() { region_name.to_string() } else { "'_".to_string() }; + if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime }; let msg = format!( "you can add a bound to the {}to make it last less than `'static` and match `{}`", diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs index 49d9caae71144..b3edc35dc3642 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -18,8 +18,8 @@ struct AllLocalUsesVisitor { } impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor { - fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) { - if *local == self.for_local { + fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) { + if local == self.for_local { self.uses.insert(location); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index 06fca4db0cf1f..b5a3081e56a7a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -106,7 +106,7 @@ enum DefUseResult { } impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { let local_ty = self.body.local_decls[local].ty; let mut found_it = false; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index fbc3a8cc088fd..fada3d45fbed8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -226,6 +226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Downcast(..) if including_downcast.0 => return None, ProjectionElem::Downcast(..) => (), + ProjectionElem::OpaqueCast(..) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -286,6 +287,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), + ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; @@ -597,16 +599,16 @@ impl UseSpans<'_> { } /// Describe the span associated with a use of a place. - pub(super) fn describe(&self) -> String { + pub(super) fn describe(&self) -> &str { match *self { UseSpans::ClosureUse { generator_kind, .. } => { if generator_kind.is_some() { - " in generator".to_string() + " in generator" } else { - " in closure".to_string() + " in closure" } } - _ => String::new(), + _ => "", } } @@ -812,12 +814,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return FnSelfUse { var_span: stmt.source_info.span, fn_call_span: *fn_span, - fn_span: self - .infcx - .tcx - .sess - .source_map() - .guess_head_span(self.infcx.tcx.def_span(method_did)), + fn_span: self.infcx.tcx.def_span(method_did), kind, }; } @@ -896,7 +893,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did); let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); - if let hir::ExprKind::Closure { body, fn_decl_span, .. } = expr { + if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr { for (captured_place, place) in self .infcx .tcx @@ -909,11 +906,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if target_place == place.as_ref() => { debug!("closure_span: found captured local {:?}", place); - let body = self.infcx.tcx.hir().body(*body); + let body = self.infcx.tcx.hir().body(body); let generator_kind = body.generator_kind(); return Some(( - *fn_decl_span, + fn_decl_span, generator_kind, captured_place.get_capture_kind_span(self.infcx.tcx), captured_place.get_path_span(self.infcx.tcx), @@ -980,14 +977,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.fn_self_span_reported.insert(fn_span) { err.span_note( // Check whether the source is accessible - if self - .infcx - .tcx - .sess - .source_map() - .span_to_snippet(self_arg.span) - .is_ok() - { + if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) { self_arg.span } else { fn_call_span diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index eb5e61fa064bd..becb81b2e26a8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -4,7 +4,7 @@ use rustc_middle::ty; use rustc_mir_dataflow::move_paths::{ IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, }; -use rustc_span::{sym, Span}; +use rustc_span::Span; use crate::diagnostics::UseSpans; use crate::prefixes::PrefixSet; @@ -218,29 +218,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn report(&mut self, error: GroupedMoveError<'tcx>) { let (mut err, err_span) = { - let (span, use_spans, original_path, kind, has_complex_bindings): ( - Span, - Option<UseSpans<'tcx>>, - Place<'tcx>, - &IllegalMoveOriginKind<'_>, - bool, - ) = match error { - GroupedMoveError::MovesFromPlace { - span, - original_path, - ref kind, - ref binds_to, - .. + let (span, use_spans, original_path, kind) = match error { + GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. } + | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => { + (span, None, original_path, kind) } - | GroupedMoveError::MovesFromValue { - span, - original_path, - ref kind, - ref binds_to, - .. - } => (span, None, original_path, kind, !binds_to.is_empty()), GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => { - (use_spans.args_or_use(), Some(use_spans), original_path, kind, false) + (use_spans.args_or_use(), Some(use_spans), original_path, kind) } }; debug!( @@ -259,7 +243,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { target_place, span, use_spans, - has_complex_bindings, ), &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { self.cannot_move_out_of_interior_of_drop(span, ty) @@ -302,7 +285,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option<UseSpans<'tcx>>, - has_complex_bindings: bool, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -399,28 +381,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } }; - let ty = move_place.ty(self.body, self.infcx.tcx).ty; - let def_id = match *ty.kind() { - ty::Adt(self_def, _) => self_def.did(), - ty::Foreign(def_id) - | ty::FnDef(def_id, _) - | ty::Closure(def_id, _) - | ty::Generator(def_id, ..) - | ty::Opaque(def_id, _) => def_id, - _ => return err, - }; - let diag_name = self.infcx.tcx.get_diagnostic_name(def_id); - if matches!(diag_name, Some(sym::Option | sym::Result)) - && use_spans.map_or(true, |v| !v.for_closure()) - && !has_complex_bindings - { - err.span_suggestion_verbose( - span.shrink_to_hi(), - &format!("consider borrowing the `{}`'s content", diag_name.unwrap()), - ".as_ref()", - Applicability::MaybeIncorrect, - ); - } else if let Some(use_spans) = use_spans { + if let Some(use_spans) = use_spans { self.explain_captures( &mut err, span, span, use_spans, move_place, None, "", "", "", false, true, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 861c5e973f1f1..cb7077fe62171 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .., ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), ], @@ -362,7 +363,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_hir_id = captured_place.get_root_variable(); - if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) + if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) && let hir::PatKind::Binding( hir::BindingAnnotation::Unannotated, _, @@ -434,8 +435,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { - let label = match local_decl.local_info.as_ref().unwrap() { - box LocalInfo::User(ClearCrossCrate::Set( + let label = match local_decl.local_info.as_deref().unwrap() { + LocalInfo::User(ClearCrossCrate::Set( mir::BindingForm::ImplicitSelf(_), )) => { let (span, suggestion) = @@ -443,7 +444,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some((true, span, suggestion)) } - box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( mir::VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info, @@ -473,20 +474,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // on for loops, RHS points to the iterator part Some(DesugaringKind::ForLoop) => { self.suggest_similar_mut_method_for_for_loop(&mut err); - Some(( - false, - opt_assignment_rhs_span.unwrap(), - format!( - "this iterator yields `{SIGIL}` {DESC}s", - SIGIL = pointer_sigil, - DESC = pointer_desc - ), - )) + err.span_label(opt_assignment_rhs_span.unwrap(), format!( + "this iterator yields `{pointer_sigil}` {pointer_desc}s", + )); + None } // don't create labels for compiler-generated spans Some(_) => None, None => { - let (span, suggestion) = if name != kw::SelfLower { + let label = if name != kw::SelfLower { suggest_ampmut( self.infcx.tcx, local_decl, @@ -501,7 +497,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. }), ))) => { - suggest_ampmut_self(self.infcx.tcx, local_decl) + let (span, sugg) = suggest_ampmut_self( + self.infcx.tcx, + local_decl, + ); + (true, span, sugg) } // explicit self (eg `self: &'a Self`) _ => suggest_ampmut( @@ -512,12 +512,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), } }; - Some((true, span, suggestion)) + Some(label) } } } - box LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( mir::VarBindingForm { binding_mode: ty::BindingMode::BindByReference(_), .. @@ -528,7 +528,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .map(|replacement| (true, pattern_span, replacement)) } - box LocalInfo::User(ClearCrossCrate::Clear) => { + LocalInfo::User(ClearCrossCrate::Clear) => { bug!("saw cleared local state") } @@ -559,7 +559,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } Some((false, err_label_span, message)) => { - err.span_label(err_label_span, &message); + err.span_label( + err_label_span, + &format!( + "consider changing this binding's type to be: `{message}`" + ), + ); } None => {} } @@ -857,7 +862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let arg_pos = args .iter() .enumerate() - .filter(|(_, arg)| arg.span == self.body.span) + .filter(|(_, arg)| arg.hir_id == closure_id) .map(|(pos, _)| pos) .next(); let def_id = hir.local_def_id(item_id); @@ -899,9 +904,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(span) = arg { err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - if self.infcx.tcx.sess.source_map().is_multiline(self.body.span) { - err.span_label(self.body.span, "in this closure"); - } + err.span_label(self.body.span, "in this closure"); look_at_return = false; } } @@ -1004,7 +1007,7 @@ fn suggest_ampmut<'tcx>( local_decl: &mir::LocalDecl<'tcx>, opt_assignment_rhs_span: Option<Span>, opt_ty_info: Option<Span>, -) -> (Span, String) { +) -> (bool, Span, String) { if let Some(assignment_rhs_span) = opt_assignment_rhs_span && let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) { @@ -1028,24 +1031,24 @@ fn suggest_ampmut<'tcx>( let lt_name = &src[1..ws_pos]; let ty = src[ws_pos..].trim_start(); if !is_mutbl(ty) { - return (assignment_rhs_span, format!("&{lt_name} mut {ty}")); + return (true, assignment_rhs_span, format!("&{lt_name} mut {ty}")); } } else if let Some(stripped) = src.strip_prefix('&') { let stripped = stripped.trim_start(); if !is_mutbl(stripped) { - return (assignment_rhs_span, format!("&mut {stripped}")); + return (true, assignment_rhs_span, format!("&mut {stripped}")); } } } - let highlight_span = match opt_ty_info { + let (suggestability, highlight_span) = match opt_ty_info { // if this is a variable binding with an explicit type, // try to highlight that for the suggestion. - Some(ty_span) => ty_span, + Some(ty_span) => (true, ty_span), // otherwise, just highlight the span associated with // the (MIR) LocalDecl. - None => local_decl.source_info.span, + None => (false, local_decl.source_info.span), }; if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) @@ -1053,12 +1056,13 @@ fn suggest_ampmut<'tcx>( { let lt_name = &src[1..ws_pos]; let ty = &src[ws_pos..]; - return (highlight_span, format!("&{} mut{}", lt_name, ty)); + return (true, highlight_span, format!("&{} mut{}", lt_name, ty)); } let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); ( + suggestability, highlight_span, if local_decl.ty.is_region_ptr() { format!("&mut {}", ty_mut.ty) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index e0f8da1c872d3..0e6a05478a07e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -19,11 +19,11 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::Region; use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::symbol::sym; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use crate::borrowck_errors; +use crate::session_diagnostics::GenericDoesNotLiveLongEnough; use super::{OutlivesSuggestionBuilder, RegionName}; use crate::region_infer::BlameConstraint; @@ -180,11 +180,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx); let origin = RelateParamBound(type_test_span, generic_ty, None); self.buffer_error(self.infcx.construct_generic_bound_failure( + self.body.source.def_id().expect_local(), type_test_span, Some(origin), type_test.generic_kind, lower_bound_region, - self.body.source.def_id().as_local(), )); } else { // FIXME. We should handle this case better. It @@ -196,9 +196,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // to report it; we could probably handle it by // iterating over the universal regions and reporting // an error that multiple bounds are required. - self.buffer_error(self.infcx.tcx.sess.struct_span_err( - type_test_span, - &format!("`{}` does not live long enough", type_test.generic_kind), + self.buffer_error(self.infcx.tcx.sess.create_err( + GenericDoesNotLiveLongEnough { + kind: type_test.generic_kind.to_string(), + span: type_test_span, + }, )); } } @@ -755,7 +757,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { return; }; - let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() }; + let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime }; let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{}`", simple_ident), @@ -767,7 +769,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.infcx.tcx, diag, fn_returns, - lifetime, + lifetime.to_string(), Some(arg), captures, Some((param.param_ty_span, param.param_ty.to_string())), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 8f3699553d92c..4cf1ac4d7abc0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -34,13 +34,13 @@ pub(crate) enum RegionNameSource { /// The `'static` region. Static, /// The free region corresponding to the environment of a closure. - SynthesizedFreeEnvRegion(Span, String), + SynthesizedFreeEnvRegion(Span, &'static str), /// The region corresponding to an argument. AnonRegionFromArgument(RegionNameHighlight), /// The region corresponding to a closure upvar. - AnonRegionFromUpvar(Span, String), + AnonRegionFromUpvar(Span, Symbol), /// The region corresponding to the return type of a closure. - AnonRegionFromOutput(RegionNameHighlight, String), + AnonRegionFromOutput(RegionNameHighlight, &'static str), /// The region from a type yielded by a generator. AnonRegionFromYieldTy(Span, String), /// An anonymous region from an async fn. @@ -110,7 +110,7 @@ impl RegionName { } RegionNameSource::SynthesizedFreeEnvRegion(span, note) => { diag.span_label(*span, format!("lifetime `{self}` represents this closure's body")); - diag.note(note); + diag.note(*note); } RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy( span, @@ -325,7 +325,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // Can't have BrEnv in functions, constants or generators. bug!("BrEnv outside of closure."); }; - let hir::ExprKind::Closure { fn_decl_span, .. } + let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) = tcx.hir().expect_expr(self.mir_hir_id()).kind else { bug!("Closure is not defined by a closure expr"); @@ -350,10 +350,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: region_name, - source: RegionNameSource::SynthesizedFreeEnvRegion( - fn_decl_span, - note.to_string(), - ), + source: RegionNameSource::SynthesizedFreeEnvRegion(fn_decl_span, note), }) } @@ -678,7 +675,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: region_name, - source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name.to_string()), + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), }) } @@ -701,16 +698,16 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) { hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure { fn_decl, body, fn_decl_span, .. }, + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }), .. }) => { let (mut span, mut hir_ty) = match fn_decl.output { hir::FnRetTy::DefaultReturn(_) => { - (tcx.sess.source_map().end_point(*fn_decl_span), None) + (tcx.sess.source_map().end_point(fn_decl_span), None) } hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)), }; - let mir_description = match hir.body(*body).generator_kind { + let mir_description = match hir.body(body).generator_kind { Some(hir::GeneratorKind::Async(gen)) => match gen { hir::AsyncGeneratorKind::Block => " of async block", hir::AsyncGeneratorKind::Closure => " of async closure", @@ -756,7 +753,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: self.synthesize_region_name(), - source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description.to_string()), + source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description), }) } @@ -841,9 +838,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let yield_span = match tcx.hir().get(self.mir_hir_id()) { hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure { fn_decl_span, .. }, + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. - }) => (tcx.sess.source_map().end_point(*fn_decl_span)), + }) => (tcx.sess.source_map().end_point(fn_decl_span)), _ => self.body.span, }; @@ -879,7 +876,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } let mut found = false; - tcx.fold_regions(tcx.type_of(body_parent_did), &mut true, |r: ty::Region<'tcx>, _| { + tcx.fold_regions(tcx.type_of(body_parent_did), |r: ty::Region<'tcx>, _| { if *r == ty::ReEarlyBound(region) { found = true; } diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 7f0a637c9d30b..22134d5a71ce1 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -40,7 +40,7 @@ pub(crate) trait AllFactsExt { impl AllFactsExt for AllFacts { /// Return fn enabled(tcx: TyCtxt<'_>) -> bool { - tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius + tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius } fn write_to_dir( diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 0425c53d9dc3c..ec521b1cf0afd 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -26,7 +26,7 @@ pub(super) fn generate_invalidates<'tcx>( if let Some(all_facts) = all_facts { let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation"); - let dominators = body.dominators(); + let dominators = body.basic_blocks.dominators(); let mut ig = InvalidationGenerator { all_facts, borrow_set, @@ -289,6 +289,10 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, operand) } + Rvalue::CopyForDeref(ref place) => { + let op = &Operand::Copy(*place); + self.consume_operand(location, op); + } Rvalue::Len(place) | Rvalue::Discriminant(place) => { let af = match *rvalue { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8ef2974c37232..15c2a9f7aefa0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,10 +2,11 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(min_specialization)] #![feature(never_type)] +#![feature(rustc_attrs)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] #![feature(try_blocks)] @@ -75,6 +76,7 @@ mod places_conflict; mod prefixes; mod region_infer; mod renumber; +mod session_diagnostics; mod type_check; mod universal_regions; mod used_muts; @@ -229,7 +231,7 @@ fn do_mir_borrowck<'a, 'tcx>( let borrow_set = Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); - let use_polonius = return_body_with_facts || infcx.tcx.sess.opts.debugging_opts.polonius; + let use_polonius = return_body_with_facts || infcx.tcx.sess.opts.unstable_opts.polonius; // Compute non-lexical lifetimes. let nll::NllOutput { @@ -332,7 +334,7 @@ fn do_mir_borrowck<'a, 'tcx>( }; } - let dominators = body.dominators(); + let dominators = body.basic_blocks.dominators(); let mut mbcx = MirBorrowckCtxt { infcx, @@ -905,6 +907,16 @@ impl InitializationRequiringAction { InitializationRequiringAction::PartialAssignment => "partially assigned", } } + + fn as_general_verb_in_past_tense(self) -> &'static str { + match self { + InitializationRequiringAction::Borrow + | InitializationRequiringAction::MatchOn + | InitializationRequiringAction::Use => "used", + InitializationRequiringAction::Assignment => "assigned", + InitializationRequiringAction::PartialAssignment => "partially assigned", + } + } } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { @@ -1224,6 +1236,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, (operand, span), flow_state) } + Rvalue::CopyForDeref(place) => { + self.access_place( + location, + (place, span), + (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + flow_state, + ); + + // Finally, check if path was already moved. + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (place.as_ref(), span), + flow_state, + ); + } Rvalue::Len(place) | Rvalue::Discriminant(place) => { let af = match *rvalue { @@ -1759,6 +1788,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | + ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => @@ -2150,6 +2180,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) => { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 3a919e954a424..d2e8227479271 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -278,9 +278,9 @@ pub(crate) fn compute_regions<'cx, 'tcx>( // Dump facts if requested. let polonius_output = all_facts.as_ref().and_then(|all_facts| { - if infcx.tcx.sess.opts.debugging_opts.nll_facts { + if infcx.tcx.sess.opts.unstable_opts.nll_facts { let def_path = infcx.tcx.def_path(def_id); - let dir_path = PathBuf::from(&infcx.tcx.sess.opts.debugging_opts.nll_facts_dir) + let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir) .join(def_path.to_filename_friendly_no_crate()); all_facts.write_to_dir(dir_path, location_table).unwrap(); } diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 97335fd0dffae..5b67e6aa1cffa 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -255,6 +255,7 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) + | (ProjectionElem::OpaqueCast { .. }, _, _) | (ProjectionElem::Downcast { .. }, _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and @@ -322,6 +323,17 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); Overlap::EqualOrDisjoint } + (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => { + if v1 == v2 { + // same type - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); + Overlap::EqualOrDisjoint + } else { + // Different types. Disjoint! + debug!("place_element_conflict: DISJOINT-OPAQUE"); + Overlap::Disjoint + } + } (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { if f1 == f2 { // same field (e.g., `a.y` vs. `a.y`) - recur. @@ -525,6 +537,7 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), _, diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index bdf2becb71126..2b50cbac9a02d 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { } ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { cursor = cursor_base; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 0fe3b45bc7c4c..9040cfcf54f41 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -19,7 +19,9 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, +}; use rustc_span::Span; use crate::{ @@ -493,8 +495,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Existential { .. } => { + NllRegionVariableOrigin::Existential { .. } => { // For existential, regions, nothing to do. } } @@ -588,7 +589,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // In Polonius mode, the errors about missing universal region relations are in the output // and need to be emitted or propagated. Otherwise, we need to check whether the // constraints were too strong, and if so, emit or propagate those errors. - if infcx.tcx.sess.opts.debugging_opts.polonius { + if infcx.tcx.sess.opts.unstable_opts.polonius { self.check_polonius_subset_errors( body, outlives_requirements.as_mut(), @@ -916,6 +917,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The idea then is to lower the `T: 'X` constraint into multiple /// bounds -- e.g., if `'X` is the union of two free lifetimes, /// `'1` and `'2`, then we would create `T: '1` and `T: '2`. + #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))] fn try_promote_type_test( &self, infcx: &InferCtxt<'_, 'tcx>, @@ -933,11 +935,41 @@ impl<'tcx> RegionInferenceContext<'tcx> { return false; }; + debug!("subject = {:?}", subject); + + let r_scc = self.constraint_sccs.scc(*lower_bound); + + debug!( + "lower_bound = {:?} r_scc={:?} universe={:?}", + lower_bound, r_scc, self.scc_universes[r_scc] + ); + + // If the type test requires that `T: 'a` where `'a` is a + // placeholder from another universe, that effectively requires + // `T: 'static`, so we have to propagate that requirement. + // + // It doesn't matter *what* universe because the promoted `T` will + // always be in the root universe. + if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() { + debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p); + let static_r = self.universal_regions.fr_static; + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject, + outlived_free_region: static_r, + blame_span: locations.span(body), + category: ConstraintCategory::Boring, + }); + + // we can return here -- the code below might push add'l constraints + // but they would all be weaker than this one. + return true; + } + // For each region outlived by lower_bound find a non-local, // universal region (it may be the same region) and add it to // `ClosureOutlivesRequirement`. - let r_scc = self.constraint_sccs.scc(*lower_bound); for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + debug!("universal_region_outlived_by ur={:?}", ur); // Check whether we can already prove that the "subject" outlives `ur`. // If so, we don't have to propagate this requirement to our caller. // @@ -962,8 +994,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { continue; } - debug!("try_promote_type_test: ur={:?}", ur); - let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur); debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub); @@ -1000,6 +1030,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// will use it's *external name*, which will be a `RegionKind` /// variant that can be used in query responses such as /// `ReEarlyBound`. + #[instrument(level = "debug", skip(self, infcx))] fn try_promote_type_test_subject( &self, infcx: &InferCtxt<'_, 'tcx>, @@ -1007,9 +1038,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option<ClosureOutlivesSubject<'tcx>> { let tcx = infcx.tcx; - debug!("try_promote_type_test_subject(ty = {:?})", ty); - - let ty = tcx.fold_regions(ty, &mut false, |r, _depth| { + let ty = tcx.fold_regions(ty, |r, _depth| { let region_vid = self.to_region_vid(r); // The challenge if this. We have some region variable `r` @@ -1289,7 +1318,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(value, &mut false, |r, _db| { + tcx.fold_regions(value, |r, _db| { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; @@ -1408,8 +1437,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_bound_universal_region(fr, placeholder, errors_buffer); } - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Existential { .. } => { + NllRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1511,8 +1539,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_bound_universal_region(fr, placeholder, errors_buffer); } - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Existential { .. } => { + NllRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1786,9 +1813,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe1.cannot_name(placeholder.universe) } - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::FreeRegion - | NllRegionVariableOrigin::Existential { .. } => false, + NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => { + false + } } } @@ -2150,8 +2177,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let blame_source = match from_region_origin { NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { from_forall: false } => true, - NllRegionVariableOrigin::RootEmptyRegion - | NllRegionVariableOrigin::Placeholder(_) + NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::Existential { from_forall: true } => false, }; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 810737587912b..7c1fa28b8dfcc 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,9 +1,20 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::DefId; use rustc_hir::OpaqueTyOrigin; +use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable}; -use rustc_trait_selection::opaque_types::InferCtxtExt; +use rustc_infer::infer::TyCtxtInferExt as _; +use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts}; +use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::{ + self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable, +}; +use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::TraitEngineExt as _; use super::RegionInferenceContext; @@ -59,7 +70,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; - let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| { + let universal_substs = infcx.tcx.fold_regions(substs, |region, _| { if let ty::RePlaceholder(..) = region.kind() { // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs. return region; @@ -91,7 +102,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { subst_regions.dedup(); let universal_concrete_type = - infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region { + infcx.tcx.fold_regions(concrete_type, |region, _| match *region { ty::ReVar(vid) => subst_regions .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) @@ -146,7 +157,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(ty, &mut false, |region, _| match *region { + tcx.fold_regions(ty, |region, _| match *region { ty::ReVar(vid) => { // Find something that we can name let upper_bound = self.approx_universal_upper_bound(vid); @@ -171,3 +182,474 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } } + +pub trait InferCtxtExt<'tcx> { + fn infer_opaque_definition_from_instantiation( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + instantiated_ty: OpaqueHiddenType<'tcx>, + origin: OpaqueTyOrigin, + ) -> Ty<'tcx>; +} + +impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { + /// Given the fully resolved, instantiated type for an opaque + /// type, i.e., the value of an inference variable like C1 or C2 + /// (*), computes the "definition type" for an opaque type + /// definition -- that is, the inferred value of `Foo1<'x>` or + /// `Foo2<'x>` that we would conceptually use in its definition: + /// ```ignore (illustrative) + /// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA + /// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB + /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } + /// ``` + /// Note that these values are defined in terms of a distinct set of + /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main + /// purpose of this function is to do that translation. + /// + /// (*) C1 and C2 were introduced in the comments on + /// `register_member_constraints`. Read that comment for more context. + /// + /// # Parameters + /// + /// - `def_id`, the `impl Trait` type + /// - `substs`, the substs used to instantiate this opaque type + /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of + /// `opaque_defn.concrete_ty` + #[instrument(level = "debug", skip(self))] + fn infer_opaque_definition_from_instantiation( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + instantiated_ty: OpaqueHiddenType<'tcx>, + origin: OpaqueTyOrigin, + ) -> Ty<'tcx> { + if self.is_tainted_by_errors() { + return self.tcx.ty_error(); + } + + let OpaqueTypeKey { def_id, substs } = opaque_type_key; + + // Use substs to build up a reverse map from regions to their + // identity mappings. This is necessary because of `impl + // Trait` lifetimes are computed by replacing existing + // 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(self.tcx, def_id); + debug!(?id_substs); + let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = + substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); + debug!("map = {:#?}", map); + + // Convert the type from the function into a type valid outside + // the function, by replacing invalid regions with 'static, + // after producing an error for each of them. + let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new( + self.tcx, + def_id, + map, + instantiated_ty.ty, + instantiated_ty.span, + )); + debug!(?definition_ty); + + if !check_opaque_type_parameter_valid( + self.tcx, + opaque_type_key, + origin, + instantiated_ty.span, + ) { + return self.tcx.ty_error(); + } + + // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` + // on stable and we'd break that. + if let OpaqueTyOrigin::TyAlias = origin { + // This logic duplicates most of `check_opaque_meets_bounds`. + // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. + let param_env = self.tcx.param_env(def_id); + let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()); + self.tcx.infer_ctxt().enter(move |infcx| { + // Require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = + ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) + .to_predicate(infcx.tcx); + let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); + + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without + // the bounds that the function supplies. + match infcx.register_hidden_type( + OpaqueTypeKey { def_id, substs: id_substs }, + ObligationCause::misc(instantiated_ty.span, body_id), + param_env, + definition_ty, + origin, + ) { + Ok(infer_ok) => { + for obligation in infer_ok.obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + } + Err(err) => { + infcx + .report_mismatched_types( + &ObligationCause::misc(instantiated_ty.span, body_id), + self.tcx.mk_opaque(def_id, id_substs), + definition_ty, + err, + ) + .emit(); + } + } + + fulfillment_cx.register_predicate_obligation( + &infcx, + Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), + ); + + // Check that all obligations are satisfied by the implementation's + // version. + let errors = fulfillment_cx.select_all_or_error(&infcx); + + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + if errors.is_empty() { + definition_ty + } else { + infcx.report_fulfillment_errors(&errors, None, false); + self.tcx.ty_error() + } + }) + } else { + definition_ty + } + } +} + +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + origin: OpaqueTyOrigin, + span: Span, +) -> bool { + match origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo<P0..Pn>() -> impl Trait + // + // into + // + // type Foo<P0...Pn> + // fn foo<P0..Pn>() -> Foo<P0...Pn>. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in opaque_type_key.substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), + GenericArgKind::Lifetime(lt) if lt.is_static() => { + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_label( + tcx.def_span(opaque_generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", + ) + .emit(); + return false; + } + GenericArgKind::Lifetime(lt) => { + matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo<u32>` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} + +struct ReverseMapper<'tcx> { + tcx: TyCtxt<'tcx>, + + opaque_type_def_id: DefId, + map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, + map_missing_regions_to_empty: bool, + + /// initially `Some`, set to `None` once error has been reported + hidden_ty: Option<Ty<'tcx>>, + + /// Span of function being checked. + span: Span, +} + +impl<'tcx> ReverseMapper<'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + opaque_type_def_id: DefId, + map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, + hidden_ty: Ty<'tcx>, + span: Span, + ) -> Self { + Self { + tcx, + opaque_type_def_id, + map, + map_missing_regions_to_empty: false, + hidden_ty: Some(hidden_ty), + span, + } + } + + fn fold_kind_mapping_missing_regions_to_empty( + &mut self, + kind: GenericArg<'tcx>, + ) -> GenericArg<'tcx> { + assert!(!self.map_missing_regions_to_empty); + self.map_missing_regions_to_empty = true; + let kind = kind.fold_with(self); + self.map_missing_regions_to_empty = false; + kind + } + + fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.map_missing_regions_to_empty); + kind.fold_with(self) + } +} + +impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + #[instrument(skip(self), level = "debug")] + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + // Ignore bound regions and `'static` regions that appear in the + // type, we only need to remap regions that reference lifetimes + // from the function declaration. + // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) | ty::ReStatic => return r, + + // If regions have been erased (by writeback), don't try to unerase + // them. + ty::ReErased => return r, + + // The regions that we expect from borrow checking. + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} + + ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { + // All of the regions in the type should either have been + // erased by writeback, or mapped back to named regions by + // borrow checking. + bug!("unexpected region kind in opaque type: {:?}", r); + } + } + + let generics = self.tcx().generics_of(self.opaque_type_def_id); + match self.map.get(&r.into()).map(|k| k.unpack()) { + Some(GenericArgKind::Lifetime(r1)) => r1, + Some(u) => panic!("region mapped to unexpected kind: {:?}", u), + None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, + None if generics.parent.is_some() => { + if let Some(hidden_ty) = self.hidden_ty.take() { + unexpected_hidden_region_diagnostic( + self.tcx, + self.tcx.def_span(self.opaque_type_def_id), + hidden_ty, + r, + ) + .emit(); + } + self.tcx.lifetimes.re_root_empty + } + None => { + self.tcx + .sess + .struct_span_err(self.span, "non-defining opaque type use in defining scope") + .span_label( + self.span, + format!( + "lifetime `{}` is part of concrete type but not used in \ + parameter list of the `impl Trait` type alias", + r + ), + ) + .emit(); + + self.tcx().lifetimes.re_static + } + } + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Closure(def_id, substs) => { + // I am a horrible monster and I pray for death. When + // we encounter a closure here, it is always a closure + // from within the function that we are currently + // type-checking -- one that is now being encapsulated + // in an opaque type. Ideally, we would + // go through the types/lifetimes that it references + // and treat them just like we would any other type, + // which means we would error out if we find any + // reference to a type/region that is not in the + // "reverse map". + // + // **However,** in the case of closures, there is a + // somewhat subtle (read: hacky) consideration. The + // problem is that our closure types currently include + // all the lifetime parameters declared on the + // enclosing function, even if they are unused by the + // closure itself. We can't readily filter them out, + // so here we replace those values with `'empty`. This + // can't really make a difference to the rest of the + // compiler; those regions are ignored for the + // outlives relation, and hence don't affect trait + // selection or auto traits, and they are erased + // during codegen. + + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_mapping_missing_regions_to_empty(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_closure(def_id, substs) + } + + ty::Generator(def_id, substs, movability) => { + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_mapping_missing_regions_to_empty(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })); + + self.tcx.mk_generator(def_id, substs, movability) + } + + ty::Param(param) => { + // Look it up in the substitution list. + match self.map.get(&ty.into()).map(|k| k.unpack()) { + // Found it in the substitution list; replace with the parameter from the + // opaque type. + Some(GenericArgKind::Type(t1)) => t1, + Some(u) => panic!("type mapped to unexpected kind: {:?}", u), + None => { + debug!(?param, ?self.map); + self.tcx + .sess + .struct_span_err( + self.span, + &format!( + "type parameter `{}` is part of concrete type but not \ + used in parameter list for the `impl Trait` type alias", + ty + ), + ) + .emit(); + + self.tcx().ty_error() + } + } + } + + _ => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + trace!("checking const {:?}", ct); + // Find a const parameter + match ct.kind() { + ty::ConstKind::Param(..) => { + // Look it up in the substitution list. + match self.map.get(&ct.into()).map(|k| k.unpack()) { + // Found it in the substitution list, replace with the parameter from the + // opaque type. + Some(GenericArgKind::Const(c1)) => c1, + Some(u) => panic!("const mapped to unexpected kind: {:?}", u), + None => { + self.tcx + .sess + .struct_span_err( + self.span, + &format!( + "const parameter `{}` is part of concrete type but not \ + used in parameter list for the `impl Trait` type alias", + ct + ), + ) + .emit(); + + self.tcx().const_error(ct.ty()) + } + } + } + + _ => ct, + } + } +} diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 2876d60527fe7..7a8ce621c5d0b 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -31,7 +31,7 @@ pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { - infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { + infcx.tcx.fold_regions(value, |_region, _depth| { let origin = NllRegionVariableOrigin::Existential { from_forall: false }; infcx.next_nll_region_var(origin) }) diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs new file mode 100644 index 0000000000000..895723d44ff1b --- /dev/null +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -0,0 +1,44 @@ +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_middle::ty::Ty; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[error(borrowck::move_unsized, code = "E0161")] +pub(crate) struct MoveUnsized<'tcx> { + pub ty: Ty<'tcx>, + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(borrowck::higher_ranked_lifetime_error)] +pub(crate) struct HigherRankedLifetimeError { + #[subdiagnostic] + pub cause: Option<HigherRankedErrorCause>, + #[primary_span] + pub span: Span, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum HigherRankedErrorCause { + #[note(borrowck::could_not_prove)] + CouldNotProve { predicate: String }, + #[note(borrowck::could_not_normalize)] + CouldNotNormalize { value: String }, +} + +#[derive(SessionDiagnostic)] +#[error(borrowck::higher_ranked_subtype_error)] +pub(crate) struct HigherRankedSubtypeError { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(borrowck::generic_does_not_live_long_enough)] +pub(crate) struct GenericDoesNotLiveLongEnough { + pub kind: String, + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 3c9e3870aeac4..3f9c0cecccc68 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Span, DUMMY_SP}; @@ -23,7 +23,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, + implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, locations: Locations, span: Span, @@ -36,7 +36,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, + implicit_region_bound: ty::Region<'tcx>, param_env: ty::ParamEnv<'tcx>, locations: Locations, span: Span, @@ -108,7 +108,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // create new region variables, which can't be done later when // verifying these bounds. if t1.has_placeholders() { - t1 = tcx.fold_regions(t1, &mut false, |r, _| match *r { + t1 = tcx.fold_regions(t1, |r, _| match *r { ty::RePlaceholder(placeholder) => { self.constraints.placeholder_region(self.infcx, placeholder) } @@ -120,7 +120,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &mut *self, tcx, region_bound_pairs, - implicit_region_bound, + Some(implicit_region_bound), param_env, ) .type_must_outlive(origin, t1, r2); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 813307356c4c7..421ef5be81287 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -61,7 +61,7 @@ pub(crate) struct CreateResult<'tcx> { pub(crate) fn create<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, + implicit_region_bound: ty::Region<'tcx>, universal_regions: &Rc<UniversalRegions<'tcx>>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { @@ -223,7 +223,7 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> { infcx: &'this InferCtxt<'this, 'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: Rc<UniversalRegions<'tcx>>, - implicit_region_bound: Option<ty::Region<'tcx>>, + implicit_region_bound: ty::Region<'tcx>, constraints: &'this mut MirTypeckRegionConstraints<'tcx>, // outputs: diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 2259a59e1956c..2a6ca5246daa9 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -230,7 +230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx, &self.borrowck_context.universal_regions, &self.region_bound_pairs, - Some(self.implicit_region_bound), + self.implicit_region_bound, self.param_env, Locations::All(DUMMY_SP), DUMMY_SP, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index b88f6e689cc80..fda2cee43fbf1 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -157,7 +157,7 @@ impl LocalUseMapBuild<'_> { } impl Visitor<'_> for LocalUseMapBuild<'_> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { if self.locals_with_use_data[local] { match def_use::categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index ac8670a513820..d5c401ae1c6ed 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -1,11 +1,11 @@ +use itertools::{Either, Itertools}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{RegionVid, TyCtxt}; -use std::rc::Rc; - use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; +use std::rc::Rc; use crate::{ constraints::OutlivesConstraintSet, @@ -46,7 +46,8 @@ pub(super) fn generate<'mir, 'tcx>( &typeck.borrowck_context.universal_regions, &typeck.borrowck_context.constraints.outlives_constraints, ); - let live_locals = compute_live_locals(typeck.tcx(), &free_regions, &body); + let (relevant_live_locals, boring_locals) = + compute_relevant_live_locals(typeck.tcx(), &free_regions, &body); let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx()); let polonius_drop_used = if facts_enabled { @@ -57,48 +58,44 @@ pub(super) fn generate<'mir, 'tcx>( None }; - if !live_locals.is_empty() || facts_enabled { - trace::trace( - typeck, - body, - elements, - flow_inits, - move_data, - live_locals, - polonius_drop_used, - ); - } + trace::trace( + typeck, + body, + elements, + flow_inits, + move_data, + relevant_live_locals, + boring_locals, + polonius_drop_used, + ); } -// The purpose of `compute_live_locals` is to define the subset of `Local` +// The purpose of `compute_relevant_live_locals` is to define the subset of `Local` // variables for which we need to do a liveness computation. We only need // to compute whether a variable `X` is live if that variable contains // some region `R` in its type where `R` is not known to outlive a free // region (i.e., where `R` may be valid for just a subset of the fn body). -fn compute_live_locals<'tcx>( +fn compute_relevant_live_locals<'tcx>( tcx: TyCtxt<'tcx>, free_regions: &FxHashSet<RegionVid>, body: &Body<'tcx>, -) -> Vec<Local> { - let live_locals: Vec<Local> = body - .local_decls - .iter_enumerated() - .filter_map(|(local, local_decl)| { +) -> (Vec<Local>, Vec<Local>) { + let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) = + body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| { if tcx.all_free_regions_meet(&local_decl.ty, |r| { free_regions.contains(&r.to_region_vid()) }) { - None + Either::Left(local) } else { - Some(local) + Either::Right(local) } - }) - .collect(); + }); debug!("{} total variables", body.local_decls.len()); - debug!("{} variables need liveness", live_locals.len()); + debug!("{} variables need liveness", relevant_live_locals.len()); debug!("{} regions outlive free regions", free_regions.len()); - live_locals + (relevant_live_locals, boring_locals) } /// Computes all regions that are (currently) known to outlive free diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs index 8070f3579194d..bc76a465e3c3a 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs @@ -54,7 +54,7 @@ impl UseFactsExtractor<'_, '_> { } impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { match def_use::categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), Some(DefUse::Use) => self.insert_use(local, location), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 169de23facce2..3795378b56861 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -3,7 +3,7 @@ use rustc_index::bit_set::HybridBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; -use rustc_middle::ty::{Ty, TypeFoldable}; +use rustc_middle::ty::{Ty, TypeVisitable}; use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -41,12 +41,13 @@ pub(super) fn trace<'mir, 'tcx>( elements: &Rc<RegionValueElements>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, - live_locals: Vec<Local>, + relevant_live_locals: Vec<Local>, + boring_locals: Vec<Local>, polonius_drop_used: Option<Vec<(Local, Location)>>, ) { debug!("trace()"); - let local_use_map = &LocalUseMap::build(&live_locals, elements, body); + let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body); let cx = LivenessContext { typeck, @@ -61,10 +62,12 @@ pub(super) fn trace<'mir, 'tcx>( let mut results = LivenessResults::new(cx); if let Some(drop_used) = polonius_drop_used { - results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect()) + results.add_extra_drop_facts(drop_used, relevant_live_locals.iter().copied().collect()) } - results.compute_for_all_locals(live_locals); + results.compute_for_all_locals(relevant_live_locals); + + results.dropck_boring_locals(boring_locals); } /// Contextual state for the type-liveness generator. @@ -133,8 +136,8 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } - fn compute_for_all_locals(&mut self, live_locals: Vec<Local>) { - for local in live_locals { + fn compute_for_all_locals(&mut self, relevant_live_locals: Vec<Local>) { + for local in relevant_live_locals { self.reset_local_state(); self.add_defs_for(local); self.compute_use_live_points_for(local); @@ -157,6 +160,24 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } + // Runs dropck for locals whose liveness isn't relevant. This is + // necessary to eagerly detect unbound recursion during drop glue computation. + fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) { + for local in boring_locals { + let local_ty = self.cx.body.local_decls[local].ty; + let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({ + let typeck = &mut self.cx.typeck; + move || LivenessContext::compute_drop_data(typeck, local_ty) + }); + + drop_data.dropck_result.report_overflows( + self.cx.typeck.infcx.tcx, + self.cx.body.local_decls[local].source_info.span, + local_ty, + ); + } + } + /// Add extra drop facts needed for Polonius. /// /// Add facts for all locals with free regions, since regions may outlive @@ -164,12 +185,12 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { fn add_extra_drop_facts( &mut self, drop_used: Vec<(Local, Location)>, - live_locals: FxHashSet<Local>, + relevant_live_locals: FxHashSet<Local>, ) { let locations = IntervalSet::new(self.cx.elements.num_points()); for (local, location) in drop_used { - if !live_locals.contains(&local) { + if !relevant_live_locals.contains(&local) { let local_ty = self.cx.body.local_decls[local].ty; if local_ty.has_free_regions() { self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); @@ -237,7 +258,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { let block = self.cx.elements.to_location(block_start).block; self.stack.extend( - self.cx.body.predecessors()[block] + self.cx.body.basic_blocks.predecessors()[block] .iter() .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)), @@ -333,7 +354,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { } let body = self.cx.body; - for &pred_block in body.predecessors()[block].iter() { + for &pred_block in body.basic_blocks.predecessors()[block].iter() { debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); // Check whether the variable is (at least partially) @@ -456,7 +477,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// points `live_at`. fn add_use_live_facts_for( &mut self, - value: impl TypeFoldable<'tcx>, + value: impl TypeVisitable<'tcx>, live_at: &IntervalSet<PointIndex>, ) { debug!("add_use_live_facts_for(value={:?})", value); @@ -521,7 +542,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { fn make_all_regions_live( elements: &RegionValueElements, typeck: &mut TypeChecker<'_, 'tcx>, - value: impl TypeFoldable<'tcx>, + value: impl TypeVisitable<'tcx>, live_at: &IntervalSet<PointIndex>, ) { debug!("make_all_regions_live(value={:?})", value); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 355254fe9429b..8e763a02af33f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -9,7 +9,6 @@ use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::vec_map::VecMap; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -28,8 +27,8 @@ use rustc_middle::mir::AssertKind; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, @@ -48,6 +47,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; +use crate::session_diagnostics::MoveUnsized; use crate::{ borrow_set::BorrowSet, constraints::{OutlivesConstraint, OutlivesConstraintSet}, @@ -157,7 +157,7 @@ pub(crate) fn type_check<'mir, 'tcx>( } = free_region_relations::create( infcx, param_env, - Some(implicit_region_bound), + implicit_region_bound, universal_regions, &mut constraints, ); @@ -333,9 +333,9 @@ struct TypeVerifier<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { - fn visit_span(&mut self, span: &Span) { + fn visit_span(&mut self, span: Span) { if !span.is_dummy() { - self.last_span = *span; + self.last_span = span; } } @@ -790,6 +790,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } PlaceTy::from_ty(fty) } + ProjectionElem::OpaqueCast(ty) => { + let ty = self.sanitize_type(place, ty); + let ty = self.cx.normalize(ty, location); + self.cx + .eq_types( + base.ty, + ty, + location.to_locations(), + ConstraintCategory::TypeAnnotation, + ) + .unwrap(); + PlaceTy::from_ty(ty) + } } } @@ -1142,7 +1155,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx, self.borrowck_context.universal_regions, self.region_bound_pairs, - Some(self.implicit_region_bound), + self.implicit_region_bound, self.param_env, locations, locations.span(self.body), @@ -1195,10 +1208,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx, self.param_env, proj, - |this, field, ()| { + |this, field, _| { let ty = this.field_ty(tcx, field); self.normalize(ty, locations) }, + |_, _| unreachable!(), ); curr_projected_ty = projected_ty; } @@ -1780,19 +1794,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // slot or local, so to find all unsized rvalues it is enough // to check all temps, return slots and locals. if self.reported_errors.replace((ty, span)).is_none() { - let mut diag = struct_span_err!( - self.tcx().sess, - span, - E0161, - "cannot move a value of type {0}: the size of {0} \ - cannot be statically determined", - ty - ); - // While this is located in `nll::typeck` this error is not // an NLL error, it's a required check to prevent creation // of unsized rvalues in a call expression. - diag.emit(); + self.tcx().sess.emit_err(MoveUnsized { ty, span }); } } } @@ -2278,6 +2283,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { self.check_operand(operand, location); } + Rvalue::CopyForDeref(place) => { + let op = &Operand::Copy(*place); + self.check_operand(op, location); + } Rvalue::BinaryOp(_, box (left, right)) | Rvalue::CheckedBinaryOp(_, box (left, right)) => { @@ -2308,6 +2317,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::BinaryOp(..) | Rvalue::CheckedBinaryOp(..) | Rvalue::NullaryOp(..) + | Rvalue::CopyForDeref(..) | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) => None, @@ -2497,6 +2507,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index c2c093f9f2fc7..2a7713bc4df3b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -503,7 +503,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let root_empty = self .infcx - .next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion) + .next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true }) .to_region_vid(); UniversalRegions { @@ -725,7 +725,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { where T: TypeFoldable<'tcx>, { - self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin)) + self.tcx.fold_regions(value, |_region, _depth| self.next_nll_region_var(origin)) } #[instrument(level = "debug", skip(self, indices))] @@ -817,9 +817,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(value, &mut false, |region, _| { - tcx.mk_region(ty::ReVar(self.to_region_vid(region))) - }) + tcx.fold_regions(value, |region, _| tcx.mk_region(ty::ReVar(self.to_region_vid(region)))) } } diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs index 1093167fa8299..8833753b12c5d 100644 --- a/compiler/rustc_borrowck/src/used_muts.rs +++ b/compiler/rustc_borrowck/src/used_muts.rs @@ -91,8 +91,8 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc self.super_statement(statement, location); } - fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { - if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) { + fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { + if place_context.is_place_assignment() && self.temporary_used_locals.contains(&local) { // Propagate the Local assigned at this Location as a used mutable local variable for moi in &self.mbcx.move_data.loc_map[location] { let mpi = &self.mbcx.move_data.moves[*moi].path; diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 7dc947f7d9a14..8d8e9d9b5ff4e 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -20,7 +20,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_expand = { path = "../rustc_expand" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 42bddd1b6edde..829eaa305e8c0 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -534,8 +534,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl let mut template_strs = Vec::with_capacity(args.templates.len()); - for template_expr in args.templates.into_iter() { - if !template.is_empty() { + for (i, template_expr) in args.templates.into_iter().enumerate() { + if i != 0 { template.push(ast::InlineAsmTemplatePiece::String("\n".to_string())); } diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index cad301812123b..01152ff7df58a 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,11 +1,10 @@ -use crate::assert::expr_if_not; use rustc_ast::{ attr, ptr::P, token, tokenstream::{DelimSpan, TokenStream, TokenTree}, - BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, Path, - PathSegment, Stmt, StructRest, UseTree, UseTreeKind, DUMMY_NODE_ID, + BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, + Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -16,11 +15,19 @@ use rustc_span::{ }; pub(super) struct Context<'cx, 'a> { + // An optimization. + // + // Elements that aren't consumed (PartialEq, PartialOrd, ...) can be copied **after** the + // `assert!` expression fails rather than copied on-the-fly. + best_case_captures: Vec<Stmt>, // Top-level `let captureN = Capture::new()` statements capture_decls: Vec<Capture>, cx: &'cx ExtCtxt<'a>, // Formatting string used for debugging fmt_string: String, + // If the current expression being visited consumes itself. Used to construct + // `best_case_captures`. + is_consumed: bool, // Top-level `let __local_bindN = &expr` statements local_bind_decls: Vec<Stmt>, // Used to avoid capturing duplicated paths @@ -36,9 +43,11 @@ pub(super) struct Context<'cx, 'a> { impl<'cx, 'a> Context<'cx, 'a> { pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self { Self { + best_case_captures: <_>::default(), capture_decls: <_>::default(), cx, fmt_string: <_>::default(), + is_consumed: true, local_bind_decls: <_>::default(), paths: <_>::default(), span, @@ -69,14 +78,22 @@ impl<'cx, 'a> Context<'cx, 'a> { self.manage_cond_expr(&mut cond_expr); let initial_imports = self.build_initial_imports(); let panic = self.build_panic(&expr_str, panic_path); + let cond_expr_with_unlikely = self.build_unlikely(cond_expr); + + let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self; - let Self { capture_decls, cx, local_bind_decls, span, .. } = self; + let mut assert_then_stmts = Vec::with_capacity(2); + assert_then_stmts.extend(best_case_captures); + assert_then_stmts.push(self.cx.stmt_expr(panic)); + let assert_then = self.cx.block(span, assert_then_stmts); let mut stmts = Vec::with_capacity(4); stmts.push(initial_imports); stmts.extend(capture_decls.into_iter().map(|c| c.decl)); stmts.extend(local_bind_decls); - stmts.push(cx.stmt_expr(expr_if_not(cx, span, cond_expr, panic, None))); + stmts.push( + cx.stmt_expr(cx.expr(span, ExprKind::If(cond_expr_with_unlikely, assert_then, None))), + ); cx.expr_block(cx.block(span, stmts)) } @@ -115,6 +132,16 @@ impl<'cx, 'a> Context<'cx, 'a> { ) } + /// Takes the conditional expression of `assert!` and then wraps it inside `unlikely` + fn build_unlikely(&self, cond_expr: P<Expr>) -> P<Expr> { + let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]); + self.cx.expr_call( + self.span, + self.cx.expr_path(self.cx.path(self.span, unlikely_path)), + vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))], + ) + } + /// The necessary custom `panic!(...)` expression. /// /// panic!( @@ -167,17 +194,39 @@ impl<'cx, 'a> Context<'cx, 'a> { /// See [Self::manage_initial_capture] and [Self::manage_try_capture] fn manage_cond_expr(&mut self, expr: &mut P<Expr>) { match (*expr).kind { - ExprKind::AddrOf(_, _, ref mut local_expr) => { - self.manage_cond_expr(local_expr); + ExprKind::AddrOf(_, mutability, ref mut local_expr) => { + self.with_is_consumed_management( + matches!(mutability, Mutability::Mut), + |this| this.manage_cond_expr(local_expr) + ); } ExprKind::Array(ref mut local_exprs) => { for local_expr in local_exprs { self.manage_cond_expr(local_expr); } } - ExprKind::Binary(_, ref mut lhs, ref mut rhs) => { - self.manage_cond_expr(lhs); - self.manage_cond_expr(rhs); + ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => { + self.with_is_consumed_management( + matches!( + op.node, + BinOpKind::Add + | BinOpKind::And + | BinOpKind::BitAnd + | BinOpKind::BitOr + | BinOpKind::BitXor + | BinOpKind::Div + | BinOpKind::Mul + | BinOpKind::Or + | BinOpKind::Rem + | BinOpKind::Shl + | BinOpKind::Shr + | BinOpKind::Sub + ), + |this| { + this.manage_cond_expr(lhs); + this.manage_cond_expr(rhs); + } + ); } ExprKind::Call(_, ref mut local_exprs) => { for local_expr in local_exprs { @@ -228,8 +277,11 @@ impl<'cx, 'a> Context<'cx, 'a> { self.manage_cond_expr(local_expr); } } - ExprKind::Unary(_, ref mut local_expr) => { - self.manage_cond_expr(local_expr); + ExprKind::Unary(un_op, ref mut local_expr) => { + self.with_is_consumed_management( + matches!(un_op, UnOp::Neg | UnOp::Not), + |this| this.manage_cond_expr(local_expr) + ); } // Expressions that are not worth or can not be captured. // @@ -242,7 +294,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Block(_, _) | ExprKind::Box(_) | ExprKind::Break(_, _) - | ExprKind::Closure(_, _, _, _, _, _) + | ExprKind::Closure(_, _, _, _, _, _, _) | ExprKind::ConstBlock(_) | ExprKind::Continue(_) | ExprKind::Err @@ -337,9 +389,23 @@ impl<'cx, 'a> Context<'cx, 'a> { )) .add_trailing_semicolon(); let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind)); - let ret = self.cx.stmt_expr(local_bind_path); - let block = self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret])); - *expr = self.cx.expr_deref(self.span, block); + let rslt = if self.is_consumed { + let ret = self.cx.stmt_expr(local_bind_path); + self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret])) + } else { + self.best_case_captures.push(try_capture_call); + local_bind_path + }; + *expr = self.cx.expr_deref(self.span, rslt); + } + + // Calls `f` with the internal `is_consumed` set to `curr_is_consumed` and then + // sets the internal `is_consumed` back to its original value. + fn with_is_consumed_management(&mut self, curr_is_consumed: bool, f: impl FnOnce(&mut Self)) { + let prev_is_consumed = self.is_consumed; + self.is_consumed = curr_is_consumed; + f(self); + self.is_consumed = prev_is_consumed; } } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index c75d83bd0a0e3..aa355150b4f81 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -36,7 +36,7 @@ pub fn expand_cfg( } #[derive(SessionDiagnostic)] -#[error(slug = "builtin-macros-requires-cfg-pattern")] +#[error(builtin_macros::requires_cfg_pattern)] struct RequiresCfgPattern { #[primary_span] #[label] @@ -44,7 +44,7 @@ struct RequiresCfgPattern { } #[derive(SessionDiagnostic)] -#[error(slug = "builtin-macros-expected-one-cfg-pattern")] +#[error(builtin_macros::expected_one_cfg_pattern)] struct OneCfgPattern { #[primary_span] span: Span, diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 12ef166b8b051..5ef68c6aeaa59 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -19,7 +19,6 @@ pub fn expand_deriving_copy( path: path_std!(marker::Copy), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: true, methods: Vec::new(), associated_types: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index c952fc0a866f8..7755ff779c4d9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -2,10 +2,10 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData}; +use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData}; +use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; pub fn expand_deriving_clone( @@ -15,23 +15,22 @@ pub fn expand_deriving_clone( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { - // check if we can use a short form + // The simple form is `fn clone(&self) -> Self { *self }`, possibly with + // some additional `AssertParamIsClone` assertions. // - // the short form is `fn clone(&self) -> Self { *self }` - // - // we can use the short form if: - // - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy) - // - there are no generic parameters (after specialization this limitation can be removed) - // if we used the short form with generics, we'd have to bound the generics with - // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something - // that is Clone but not Copy. and until specialization we can't write both impls. - // - the item is a union with Copy fields - // Unions with generic parameters still can derive Clone because they require Copy - // for deriving, Clone alone is not enough. - // Wherever Clone is implemented for fields is irrelevant so we don't assert it. + // We can use the simple form if either of the following are true. + // - The type derives Copy and there are no generic parameters. (If we + // used the simple form with generics, we'd have to bound the generics + // with Clone + Copy, and then there'd be no Clone impl at all if the + // user fills in something that is Clone but not Copy. After + // specialization we can remove this no-generics limitation.) + // - The item is a union. (Unions with generic parameters still can derive + // Clone because they require Copy for deriving, Clone alone is not + // enough. Whether Clone is implemented for fields is irrelevant so we + // don't assert it.) let bounds; let substructure; - let is_shallow; + let is_simple; match *item { Annotatable::Item(ref annitem) => match annitem.kind { ItemKind::Struct(_, Generics { ref params, .. }) @@ -44,30 +43,25 @@ pub fn expand_deriving_clone( .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) { bounds = vec![]; - is_shallow = true; + is_simple = true; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_shallow("Clone", c, s, sub, false) + cs_clone_simple("Clone", c, s, sub, false) })); } else { bounds = vec![]; - is_shallow = false; + is_simple = false; substructure = combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); } } ItemKind::Union(..) => { - bounds = vec![Literal(path_std!(marker::Copy))]; - is_shallow = true; + bounds = vec![Path(path_std!(marker::Copy))]; + is_simple = true; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_shallow("Clone", c, s, sub, true) + cs_clone_simple("Clone", c, s, sub, true) })); } - _ => { - bounds = vec![]; - is_shallow = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); - } + _ => cx.span_bug(span, "`#[derive(Clone)]` on wrong item kind"), }, _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), @@ -81,80 +75,80 @@ pub fn expand_deriving_clone( path: path_std!(clone::Clone), additional_bounds: bounds, generics: Bounds::empty(), - is_unsafe: false, supports_unions: true, methods: vec![MethodDef { name: sym::clone, generics: Bounds::empty(), - explicit_self: borrowed_explicit_self(), - args: Vec::new(), + explicit_self: true, + nonself_args: Vec::new(), ret_ty: Self_, attributes: attrs, - is_unsafe: false, unify_fieldless_variants: false, combine_substructure: substructure, }], associated_types: Vec::new(), }; - trait_def.expand_ext(cx, mitem, item, push, is_shallow) + trait_def.expand_ext(cx, mitem, item, push, is_simple) } -fn cs_clone_shallow( +fn cs_clone_simple( name: &str, cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, is_union: bool, -) -> P<Expr> { - fn assert_ty_bounds( - cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, - ty: P<ast::Ty>, - span: Span, - helper_name: &str, - ) { - // Generate statement `let _: helper_name<ty>;`, - // set the expn ID so we can use the unstable struct. - let span = cx.with_def_site_ctxt(span); - let assert_path = cx.path_all( - span, - true, - cx.std_path(&[sym::clone, Symbol::intern(helper_name)]), - vec![GenericArg::Type(ty)], - ); - stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); - } - fn process_variant(cx: &mut ExtCtxt<'_>, stmts: &mut Vec<ast::Stmt>, variant: &VariantData) { +) -> BlockOrExpr { + let mut stmts = Vec::new(); + let mut seen_type_names = FxHashSet::default(); + let mut process_variant = |variant: &VariantData| { for field in variant.fields() { - // let _: AssertParamIsClone<FieldTy>; - assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsClone"); + // This basic redundancy checking only prevents duplication of + // assertions like `AssertParamIsClone<Foo>` where the type is a + // simple name. That's enough to get a lot of cases, though. + if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) { + // Already produced an assertion for this type. + } else { + // let _: AssertParamIsClone<FieldTy>; + super::assert_ty_bounds( + cx, + &mut stmts, + field.ty.clone(), + field.span, + &[sym::clone, sym::AssertParamIsClone], + ); + } } - } + }; - let mut stmts = Vec::new(); if is_union { + // Just a single assertion for unions, that the union impls `Copy`. // let _: AssertParamIsCopy<Self>; let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper))); - assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy"); + super::assert_ty_bounds( + cx, + &mut stmts, + self_ty, + trait_span, + &[sym::clone, sym::AssertParamIsCopy], + ); } else { match *substr.fields { StaticStruct(vdata, ..) => { - process_variant(cx, &mut stmts, vdata); + process_variant(vdata); } StaticEnum(enum_def, ..) => { for variant in &enum_def.variants { - process_variant(cx, &mut stmts, &variant.data); + process_variant(&variant.data); } } _ => cx.span_bug( trait_span, - &format!("unexpected substructure in shallow `derive({})`", name), + &format!("unexpected substructure in simple `derive({})`", name), ), } } - stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); - cx.expr_block(cx.block(trait_span, stmts)) + BlockOrExpr::new_mixed(stmts, Some(cx.expr_deref(trait_span, cx.expr_self(trait_span)))) } fn cs_clone( @@ -162,12 +156,12 @@ fn cs_clone( cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, -) -> P<Expr> { +) -> BlockOrExpr { let ctor_path; let all_fields; let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]); - let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo<'_>| { - let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; + let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| { + let args = vec![field.self_expr.clone()]; cx.expr_call_global(field.span, fn_path.clone(), args) }; @@ -183,15 +177,13 @@ fn cs_clone( all_fields = af; vdata = &variant.data; } - EnumNonMatchingCollapsed(..) => { - cx.span_bug(trait_span, &format!("non-matching enum variants in `derive({})`", name,)) - } + EnumTag(..) => cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)), StaticEnum(..) | StaticStruct(..) => { cx.span_bug(trait_span, &format!("associated function in `derive({})`", name)) } } - match *vdata { + let expr = match *vdata { VariantData::Struct(..) => { let fields = all_fields .iter() @@ -215,5 +207,6 @@ fn cs_clone( cx.expr_call(trait_span, path, subcalls) } VariantData::Unit(..) => cx.expr_path(ctor_path), - } + }; + BlockOrExpr::new_expr(expr) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 54ab88dc3ffc9..4e798bf6acb10 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -2,10 +2,10 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, GenericArg, MetaItem}; +use rustc_ast::{self as ast, MetaItem}; +use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; pub fn expand_deriving_eq( @@ -27,16 +27,14 @@ pub fn expand_deriving_eq( path: path_std!(cmp::Eq), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: true, methods: vec![MethodDef { name: sym::assert_receiver_is_total_eq, generics: Bounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![], - ret_ty: nil_ty(), + explicit_self: true, + nonself_args: vec![], + ret_ty: Unit, attributes: attrs, - is_unsafe: false, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { cs_total_eq_assert(a, b, c) @@ -54,47 +52,39 @@ fn cs_total_eq_assert( cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, -) -> P<Expr> { - fn assert_ty_bounds( - cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, - ty: P<ast::Ty>, - span: Span, - helper_name: &str, - ) { - // Generate statement `let _: helper_name<ty>;`, - // set the expn ID so we can use the unstable struct. - let span = cx.with_def_site_ctxt(span); - let assert_path = cx.path_all( - span, - true, - cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]), - vec![GenericArg::Type(ty)], - ); - stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); - } - fn process_variant( - cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, - variant: &ast::VariantData, - ) { +) -> BlockOrExpr { + let mut stmts = Vec::new(); + let mut seen_type_names = FxHashSet::default(); + let mut process_variant = |variant: &ast::VariantData| { for field in variant.fields() { - // let _: AssertParamIsEq<FieldTy>; - assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsEq"); + // This basic redundancy checking only prevents duplication of + // assertions like `AssertParamIsEq<Foo>` where the type is a + // simple name. That's enough to get a lot of cases, though. + if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) { + // Already produced an assertion for this type. + } else { + // let _: AssertParamIsEq<FieldTy>; + super::assert_ty_bounds( + cx, + &mut stmts, + field.ty.clone(), + field.span, + &[sym::cmp, sym::AssertParamIsEq], + ); + } } - } + }; - let mut stmts = Vec::new(); match *substr.fields { StaticStruct(vdata, ..) => { - process_variant(cx, &mut stmts, vdata); + process_variant(vdata); } StaticEnum(enum_def, ..) => { for variant in &enum_def.variants { - process_variant(cx, &mut stmts, &variant.data); + process_variant(&variant.data); } } _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"), } - cx.expr_block(cx.block(trait_span, stmts)) + BlockOrExpr::new_stmts(stmts) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 2b3ac0a86c16c..1612be862377b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, MetaItem}; +use rustc_ast::MetaItem; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -23,16 +22,14 @@ pub fn expand_deriving_ord( path: path_std!(cmp::Ord), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![MethodDef { name: sym::cmp, generics: Bounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), sym::other)], - ret_ty: Literal(path_std!(cmp::Ordering)), + explicit_self: true, + nonself_args: vec![(self_ref(), sym::other)], + ret_ty: Path(path_std!(cmp::Ordering)), attributes: attrs, - is_unsafe: false, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))), }], @@ -42,72 +39,41 @@ pub fn expand_deriving_ord( trait_def.expand(cx, mitem, item, push) } -pub fn ordering_collapsed( - cx: &mut ExtCtxt<'_>, - span: Span, - self_arg_tags: &[Ident], -) -> P<ast::Expr> { - let lft = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[0])); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); - let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); - cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt]) -} - -pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { +pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); - let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); - + let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]); // Builds: // - // match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { - // ::std::cmp::Ordering::Equal => - // match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { - // ::std::cmp::Ordering::Equal => { - // ... + // match ::core::cmp::Ord::cmp(&self.x, &other.x) { + // ::std::cmp::Ordering::Equal => + // ::core::cmp::Ord::cmp(&self.y, &other.y), + // cmp => cmp, // } - // cmp => cmp - // }, - // cmp => cmp - // } - // - cs_fold( + let expr = cs_fold( // foldr nests the if-elses correctly, leaving the first field // as the outermost one, and the last as the innermost. false, - |cx, span, old, self_f, other_fs| { - // match new { - // ::std::cmp::Ordering::Equal => old, - // cmp => cmp - // } - - let new = { - let [other_f] = other_fs else { - cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"); - }; - - let args = - vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())]; - - cx.expr_call_global(span, cmp_path.clone(), args) - }; - - let eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old); - let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - cx.expr_path(equals_path.clone()), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`") - } else { - ordering_collapsed(cx, span, tag_tuple) - } - }), cx, span, substr, - ) + |cx, fold| match fold { + CsFold::Single(field) => { + let [other_expr] = &field.other_selflike_exprs[..] else { + cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); + }; + let args = vec![field.self_expr.clone(), other_expr.clone()]; + cx.expr_call_global(field.span, cmp_path.clone(), args) + } + CsFold::Combine(span, expr1, expr2) => { + let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1); + let neq_arm = + cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); + cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + } + CsFold::Fieldless => cx.expr_path(equal_path.clone()), + }, + ); + BlockOrExpr::new_expr(expr) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index eead8b37024c0..0141b33772621 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -3,7 +3,7 @@ use crate::deriving::generic::*; use crate::deriving::{path_local, path_std}; use rustc_ast::ptr::P; -use rustc_ast::{BinOpKind, Expr, MetaItem}; +use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -15,8 +15,6 @@ pub fn expand_deriving_partial_eq( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { - // structures are equal if all fields are equal, and non equal, if - // any fields are not equal or if the enum variants are different fn cs_op( cx: &mut ExtCtxt<'_>, span: Span, @@ -24,41 +22,44 @@ pub fn expand_deriving_partial_eq( op: BinOpKind, combiner: BinOpKind, base: bool, - ) -> P<Expr> { - let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| { - let [other_f] = other_fs else { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"); - }; - - cx.expr_binary(span, op, self_f, other_f.clone()) - }; - - cs_fold1( + ) -> BlockOrExpr { + let expr = cs_fold( true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let eq = op(cx, span, self_f, other_fs); - cx.expr_binary(span, combiner, subexpr, eq) - }, - |cx, args| { - match args { - Some((span, self_f, other_fs)) => { - // Special-case the base case to generate cleaner code. - op(cx, span, self_f, other_fs) - } - None => cx.expr_bool(span, base), - } - }, - Box::new(|cx, span, _, _| cx.expr_bool(span, !base)), cx, span, substr, - ) + |cx, fold| match fold { + CsFold::Single(field) => { + let [other_expr] = &field.other_selflike_exprs[..] else { + cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); + }; + + // We received `&T` arguments. Convert them to `T` by + // stripping `&` or adding `*`. This isn't necessary for + // type checking, but it results in much better error + // messages if something goes wrong. + let convert = |expr: &P<Expr>| { + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = + &expr.kind + { + inner.clone() + } else { + cx.expr_deref(field.span, expr.clone()) + } + }; + cx.expr_binary(field.span, op, convert(&field.self_expr), convert(other_expr)) + } + CsFold::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2), + CsFold::Fieldless => cx.expr_bool(span, base), + }, + ); + BlockOrExpr::new_expr(expr) } - fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { + fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true) } - fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { + fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false) } @@ -69,11 +70,10 @@ pub fn expand_deriving_partial_eq( MethodDef { name: $name, generics: Bounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), sym::other)], - ret_ty: Literal(path_local!(bool)), + explicit_self: true, + nonself_args: vec![(self_ref(), sym::other)], + ret_ty: Path(path_local!(bool)), attributes: attrs, - is_unsafe: false, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))), } @@ -102,7 +102,6 @@ pub fn expand_deriving_partial_eq( path: path_std!(cmp::PartialEq), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods, associated_types: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index d28ac822a1ed9..2ebb01cc8a035 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::ptr::P; -use rustc_ast::{Expr, MetaItem}; +use rustc_ast::MetaItem; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -15,13 +14,9 @@ pub fn expand_deriving_partial_ord( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { - let ordering_ty = Literal(path_std!(cmp::Ordering)); - let ret_ty = Literal(Path::new_( - pathvec_std!(option::Option), - None, - vec![Box::new(ordering_ty)], - PathKind::Std, - )); + let ordering_ty = Path(path_std!(cmp::Ordering)); + let ret_ty = + Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); let inline = cx.meta_word(span, sym::inline); let attrs = vec![cx.attribute(inline)]; @@ -29,11 +24,10 @@ pub fn expand_deriving_partial_ord( let partial_cmp_def = MethodDef { name: sym::partial_cmp, generics: Bounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(borrowed_self(), sym::other)], + explicit_self: true, + nonself_args: vec![(self_ref(), sym::other)], ret_ty, attributes: attrs, - is_unsafe: false, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr) @@ -46,7 +40,6 @@ pub fn expand_deriving_partial_ord( path: path_std!(cmp::PartialOrd), additional_bounds: vec![], generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![partial_cmp_def], associated_types: Vec::new(), @@ -54,67 +47,42 @@ pub fn expand_deriving_partial_ord( trait_def.expand(cx, mitem, item, push) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { +pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); - let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); - let ordering_expr = cx.expr_path(ordering.clone()); - let equals_expr = cx.expr_some(span, ordering_expr); - + let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); // Builds: // - // match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { - // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => - // match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { - // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { - // ... - // } - // cmp => cmp - // }, - // cmp => cmp + // match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) { + // ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + // ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y), + // cmp => cmp, // } - // - cs_fold( + let expr = cs_fold( // foldr nests the if-elses correctly, leaving the first field // as the outermost one, and the last as the innermost. false, - |cx, span, old, self_f, other_fs| { - // match new { - // Some(::std::cmp::Ordering::Equal) => old, - // cmp => cmp - // } - - let new = { - let [other_f] = other_fs else { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"); - }; - - let args = - vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())]; - - cx.expr_call_global(span, partial_cmp_path.clone(), args) - }; - - let eq_arm = cx.arm(span, cx.pat_some(span, cx.pat_path(span, ordering.clone())), old); - let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - equals_expr, - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0])); - let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1])); - let fn_partial_cmp_path = - cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); - cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt]) - } - }), cx, span, substr, - ) + |cx, fold| match fold { + CsFold::Single(field) => { + let [other_expr] = &field.other_selflike_exprs[..] else { + cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); + }; + let args = vec![field.self_expr.clone(), other_expr.clone()]; + cx.expr_call_global(field.span, partial_cmp_path.clone(), args) + } + CsFold::Combine(span, expr1, expr2) => { + let eq_arm = + cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); + let neq_arm = + cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); + cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + } + CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())), + }, + ); + BlockOrExpr::new_expr(expr) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index ecf70da6d96c5..ceef893e862eb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -2,15 +2,10 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, LocalKind, MetaItem}; +use rustc_ast::{self as ast, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; - -fn make_mut_borrow(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<Expr>) -> P<Expr> { - cx.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Mut, expr)) -} +use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::Span; pub fn expand_deriving_debug( cx: &mut ExtCtxt<'_>, @@ -20,8 +15,7 @@ pub fn expand_deriving_debug( push: &mut dyn FnMut(Annotatable), ) { // &mut ::std::fmt::Formatter - let fmtr = - Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut)); + let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut); let trait_def = TraitDef { span, @@ -29,16 +23,14 @@ pub fn expand_deriving_debug( path: path_std!(fmt::Debug), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![MethodDef { name: sym::fmt, generics: Bounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec![(fmtr, sym::f)], - ret_ty: Literal(path_std!(fmt::Result)), + explicit_self: true, + nonself_args: vec![(fmtr, sym::f)], + ret_ty: Path(path_std!(fmt::Result)), attributes: Vec::new(), - is_unsafe: false, unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { show_substructure(a, b, c) @@ -49,15 +41,11 @@ pub fn expand_deriving_debug( trait_def.expand(cx, mitem, item, push) } -/// We use the debug builders to do the heavy lifting here -fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> { - // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() - // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() - // based on the "shape". +fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { let (ident, vdata, fields) = match substr.fields { Struct(vdata, fields) => (substr.type_ident, *vdata, fields), EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields), - EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { + EnumTag(..) | StaticStruct(..) | StaticEnum(..) => { cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") } }; @@ -65,95 +53,129 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> // We want to make sure we have the ctxt set so that we can use unstable methods let span = cx.with_def_site_ctxt(span); let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); - let fmt = substr.nonself_args[0].clone(); - - // Special fast path for unit variants. In the common case of an enum that is entirely unit - // variants (i.e. a C-like enum), this fast path allows LLVM to eliminate the entire switch in - // favor of a lookup table. - if let ast::VariantData::Unit(..) = vdata { - let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]); - let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]); - let stmts = vec![cx.stmt_expr(expr)]; - let block = cx.block(span, stmts); - return cx.expr_block(block); - } + let fmt = substr.nonselflike_args[0].clone(); - let builder = Ident::new(sym::debug_trait_builder, span); - let builder_expr = cx.expr_ident(span, builder); - - let mut stmts = Vec::with_capacity(fields.len() + 2); - let fn_path_finish; - match vdata { + // Struct and tuples are similar enough that we use the same code for both, + // with some extra pieces for structs due to the field names. + let (is_struct, args_per_field) = match vdata { ast::VariantData::Unit(..) => { - cx.span_bug(span, "unit variants should have been handled above"); + // Special fast path for unit variants. + assert!(fields.is_empty()); + (false, 0) } - ast::VariantData::Tuple(..) => { - // tuple struct/"normal" variant - let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]); - let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]); - let expr = make_mut_borrow(cx, span, expr); - stmts.push(cx.stmt_let(span, false, builder, expr)); - - for field in fields { - // Use double indirection to make sure this works for unsized types - let field = cx.expr_addr_of(field.span, field.self_.clone()); - let field = cx.expr_addr_of(field.span, field); - - let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::field]); - let expr = - cx.expr_call_global(span, fn_path_field, vec![builder_expr.clone(), field]); - - // Use `let _ = expr;` to avoid triggering the - // unused_results lint. - stmts.push(stmt_let_underscore(cx, span, expr)); - } + ast::VariantData::Tuple(..) => (false, 1), + ast::VariantData::Struct(..) => (true, 2), + }; - fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::finish]); - } - ast::VariantData::Struct(..) => { - // normal struct/struct variant - let fn_path_debug_struct = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_struct]); - let expr = cx.expr_call_global(span, fn_path_debug_struct, vec![fmt, name]); - let expr = make_mut_borrow(cx, span, expr); - stmts.push(cx.stmt_let(DUMMY_SP, false, builder, expr)); - - for field in fields { + // The number of fields that can be handled without an array. + const CUTOFF: usize = 5; + + if fields.is_empty() { + // Special case for no fields. + let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]); + let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]); + BlockOrExpr::new_expr(expr) + } else if fields.len() <= CUTOFF { + // Few enough fields that we can use a specific-length method. + let debug = if is_struct { + format!("debug_struct_field{}_finish", fields.len()) + } else { + format!("debug_tuple_field{}_finish", fields.len()) + }; + let fn_path_debug = cx.std_path(&[sym::fmt, sym::Formatter, Symbol::intern(&debug)]); + + let mut args = Vec::with_capacity(2 + fields.len() * args_per_field); + args.extend([fmt, name]); + for i in 0..fields.len() { + let field = &fields[i]; + if is_struct { let name = cx.expr_lit( field.span, ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked), ); - - // Use double indirection to make sure this works for unsized types - let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::field]); - let field = cx.expr_addr_of(field.span, field.self_.clone()); - let field = cx.expr_addr_of(field.span, field); - let expr = cx.expr_call_global( - span, - fn_path_field, - vec![builder_expr.clone(), name, field], - ); - stmts.push(stmt_let_underscore(cx, span, expr)); + args.push(name); } - fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::finish]); + // Use an extra indirection to make sure this works for unsized types. + let field = cx.expr_addr_of(field.span, field.self_expr.clone()); + args.push(field); } - } + let expr = cx.expr_call_global(span, fn_path_debug, args); + BlockOrExpr::new_expr(expr) + } else { + // Enough fields that we must use the any-length method. + let mut name_exprs = Vec::with_capacity(fields.len()); + let mut value_exprs = Vec::with_capacity(fields.len()); + + for field in fields { + if is_struct { + name_exprs.push(cx.expr_lit( + field.span, + ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked), + )); + } - let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_expr]); + // Use an extra indirection to make sure this works for unsized types. + let field = cx.expr_addr_of(field.span, field.self_expr.clone()); + value_exprs.push(field); + } - stmts.push(cx.stmt_expr(expr)); - let block = cx.block(span, stmts); - cx.expr_block(block) -} + // `let names: &'static _ = &["field1", "field2"];` + let names_let = if is_struct { + let lt_static = Some(cx.lifetime_static(span)); + let ty_static_ref = + cx.ty_rptr(span, cx.ty_infer(span), lt_static, ast::Mutability::Not); + Some(cx.stmt_let_ty( + span, + false, + Ident::new(sym::names, span), + Some(ty_static_ref), + cx.expr_array_ref(span, name_exprs), + )) + } else { + None + }; + + // `let values: &[&dyn Debug] = &[&&self.field1, &&self.field2];` + let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug])); + let ty_dyn_debug = cx.ty( + span, + ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn), + ); + let ty_slice = cx.ty( + span, + ast::TyKind::Slice(cx.ty_rptr(span, ty_dyn_debug, None, ast::Mutability::Not)), + ); + let values_let = cx.stmt_let_ty( + span, + false, + Ident::new(sym::values, span), + Some(cx.ty_rptr(span, ty_slice, None, ast::Mutability::Not)), + cx.expr_array_ref(span, value_exprs), + ); + + // `fmt::Formatter::debug_struct_fields_finish(fmt, name, names, values)` or + // `fmt::Formatter::debug_tuple_fields_finish(fmt, name, values)` + let sym_debug = if is_struct { + sym::debug_struct_fields_finish + } else { + sym::debug_tuple_fields_finish + }; + let fn_path_debug_internal = cx.std_path(&[sym::fmt, sym::Formatter, sym_debug]); + + let mut args = Vec::with_capacity(4); + args.push(fmt); + args.push(name); + if is_struct { + args.push(cx.expr_ident(span, Ident::new(sym::names, span))); + } + args.push(cx.expr_ident(span, Ident::new(sym::values, span))); + let expr = cx.expr_call_global(span, fn_path_debug_internal, args); -fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt { - let local = P(ast::Local { - pat: cx.pat_wild(sp), - ty: None, - id: ast::DUMMY_NODE_ID, - kind: LocalKind::Init(expr), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + let mut stmts = Vec::with_capacity(3); + if is_struct { + stmts.push(names_let.unwrap()); + } + stmts.push(values_let); + BlockOrExpr::new_mixed(stmts, Some(expr)) + } } diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 1d892b20729d5..d688143a2a5c6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -23,40 +23,32 @@ pub fn expand_deriving_rustc_decodable( let trait_def = TraitDef { span, attributes: Vec::new(), - path: Path::new_(vec![krate, sym::Decodable], None, vec![], PathKind::Global), + path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![MethodDef { name: sym::decode, generics: Bounds { bounds: vec![( typaram, - vec![Path::new_(vec![krate, sym::Decoder], None, vec![], PathKind::Global)], + vec![Path::new_(vec![krate, sym::Decoder], vec![], PathKind::Global)], )], }, - explicit_self: None, - args: vec![( - Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)), + explicit_self: false, + nonself_args: vec![( + Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::d, )], - ret_ty: Literal(Path::new_( + ret_ty: Path(Path::new_( pathvec_std!(result::Result), - None, vec![ Box::new(Self_), - Box::new(Literal(Path::new_( - vec![typaram, sym::Error], - None, - vec![], - PathKind::Local, - ))), + Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), ], PathKind::Std, )), attributes: Vec::new(), - is_unsafe: false, unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { decodable_substructure(a, b, c, krate) @@ -73,8 +65,8 @@ fn decodable_substructure( trait_span: Span, substr: &Substructure<'_>, krate: Symbol, -) -> P<Expr> { - let decoder = substr.nonself_args[0].clone(); +) -> BlockOrExpr { + let decoder = substr.nonselflike_args[0].clone(); let recurse = vec![ Ident::new(krate, trait_span), Ident::new(sym::Decodable, trait_span), @@ -85,7 +77,7 @@ fn decodable_substructure( let blkarg = Ident::new(sym::_d, trait_span); let blkdecoder = cx.expr_ident(trait_span, blkarg); - match *substr.fields { + let expr = match *substr.fields { StaticStruct(_, ref summary) => { let nfields = match *summary { Unnamed(ref fields, _) => fields.len(), @@ -162,14 +154,13 @@ fn decodable_substructure( cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms), ); let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); - let variant_vec = cx.expr_vec(trait_span, variants); - let variant_vec = cx.expr_addr_of(trait_span, variant_vec); + let variant_array_ref = cx.expr_array_ref(trait_span, variants); let fn_read_enum_variant_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]); let result = cx.expr_call_global( trait_span, fn_read_enum_variant_path, - vec![blkdecoder, variant_vec, lambda], + vec![blkdecoder, variant_array_ref, lambda], ); let fn_read_enum_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]); @@ -185,7 +176,8 @@ fn decodable_substructure( ) } _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), - } + }; + BlockOrExpr::new_expr(expr) } /// Creates a decoder for a single enum variant/struct: diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index b49331e28753d..5177690917f21 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,11 +1,10 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; -use rustc_ast::ptr::P; +use rustc_ast as ast; use rustc_ast::walk_list; use rustc_ast::EnumDef; use rustc_ast::VariantData; -use rustc_ast::{Expr, MetaItem}; use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; @@ -16,7 +15,7 @@ use smallvec::SmallVec; pub fn expand_deriving_default( cx: &mut ExtCtxt<'_>, span: Span, - mitem: &MetaItem, + mitem: &ast::MetaItem, item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { @@ -30,16 +29,14 @@ pub fn expand_deriving_default( path: Path::new(vec![kw::Default, sym::Default]), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![MethodDef { name: kw::Default, generics: Bounds::empty(), - explicit_self: None, - args: Vec::new(), + explicit_self: false, + nonself_args: Vec::new(), ret_ty: Self_, attributes: attrs, - is_unsafe: false, unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| { match substr.fields { @@ -61,12 +58,12 @@ fn default_struct_substructure( trait_span: Span, substr: &Substructure<'_>, summary: &StaticFields, -) -> P<Expr> { +) -> BlockOrExpr { // Note that `kw::Default` is "default" and `sym::Default` is "Default"! let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); - match summary { + let expr = match summary { Unnamed(ref fields, is_tuple) => { if !is_tuple { cx.expr_ident(trait_span, substr.type_ident) @@ -82,31 +79,27 @@ fn default_struct_substructure( .collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) } - } + }; + BlockOrExpr::new_expr(expr) } fn default_enum_substructure( cx: &mut ExtCtxt<'_>, trait_span: Span, enum_def: &EnumDef, -) -> P<Expr> { - let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) else { - return DummyResult::raw_expr(trait_span, true); +) -> BlockOrExpr { + let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) + && let Ok(_) = validate_default_attribute(cx, default_variant) + { + // We now know there is exactly one unit variant with exactly one `#[default]` attribute. + cx.expr_path(cx.path( + default_variant.span, + vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], + )) + } else { + DummyResult::raw_expr(trait_span, true) }; - - // At this point, we know that there is exactly one variant with a `#[default]` attribute. The - // attribute hasn't yet been validated. - - if let Err(()) = validate_default_attribute(cx, default_variant) { - return DummyResult::raw_expr(trait_span, true); - } - - // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - - cx.expr_path(cx.path( - default_variant.span, - vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], - )) + BlockOrExpr::new_expr(expr) } fn extract_default_variant<'a>( diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 6151a80a56d58..70167cac68a7e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -89,8 +89,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec_std; -use rustc_ast::ptr::P; -use rustc_ast::{Expr, ExprKind, MetaItem, Mutability}; +use rustc_ast::{ExprKind, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -108,40 +107,32 @@ pub fn expand_deriving_rustc_encodable( let trait_def = TraitDef { span, attributes: Vec::new(), - path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global), + path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![MethodDef { name: sym::encode, generics: Bounds { bounds: vec![( typaram, - vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)], + vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)], )], }, - explicit_self: borrowed_explicit_self(), - args: vec![( - Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)), + explicit_self: true, + nonself_args: vec![( + Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::s, )], - ret_ty: Literal(Path::new_( + ret_ty: Path(Path::new_( pathvec_std!(result::Result), - None, vec![ - Box::new(Tuple(Vec::new())), - Box::new(Literal(Path::new_( - vec![typaram, sym::Error], - None, - vec![], - PathKind::Local, - ))), + Box::new(Unit), + Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), ], PathKind::Std, )), attributes: Vec::new(), - is_unsafe: false, unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { encodable_substructure(a, b, c, krate) @@ -158,8 +149,8 @@ fn encodable_substructure( trait_span: Span, substr: &Substructure<'_>, krate: Symbol, -) -> P<Expr> { - let encoder = substr.nonself_args[0].clone(); +) -> BlockOrExpr { + let encoder = substr.nonselflike_args[0].clone(); // throw an underscore in front to suppress unused variable warnings let blkarg = Ident::new(sym::_e, trait_span); let blkencoder = cx.expr_ident(trait_span, blkarg); @@ -177,12 +168,12 @@ fn encodable_substructure( let fn_emit_struct_field_path = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]); let mut stmts = Vec::new(); - for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() { + for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() { let name = match name { Some(id) => id.name, None => Symbol::intern(&format!("_field{}", i)), }; - let self_ref = cx.expr_addr_of(span, self_.clone()); + let self_ref = cx.expr_addr_of(span, self_expr.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_call_global( @@ -219,7 +210,7 @@ fn encodable_substructure( let fn_emit_struct_path = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]); - cx.expr_call_global( + let expr = cx.expr_call_global( trait_span, fn_emit_struct_path, vec![ @@ -228,7 +219,8 @@ fn encodable_substructure( cx.expr_usize(trait_span, fields.len()), blk, ], - ) + ); + BlockOrExpr::new_expr(expr) } EnumMatching(idx, _, variant, ref fields) => { @@ -245,8 +237,8 @@ fn encodable_substructure( let mut stmts = Vec::new(); if !fields.is_empty() { let last = fields.len() - 1; - for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { - let self_ref = cx.expr_addr_of(span, self_.clone()); + for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { + let self_ref = cx.expr_addr_of(span, self_expr.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda1(span, enc, blkarg); @@ -290,12 +282,12 @@ fn encodable_substructure( let blk = cx.lambda1(trait_span, call, blkarg); let fn_emit_enum_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]); - let ret = cx.expr_call_global( + let expr = cx.expr_call_global( trait_span, fn_emit_enum_path, vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], ); - cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)])) + BlockOrExpr::new_mixed(vec![me], Some(expr)) } _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 53369afae278c..076b627ca79f6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -21,21 +21,14 @@ //! `struct T(i32, char)`). //! - `EnumMatching`, when `Self` is an enum and all the arguments are the //! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`) -//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments -//! are not the same variant (e.g., `None`, `Some(1)` and `None`). +//! - `EnumTag` when `Self` is an enum, for comparing the enum tags. //! - `StaticEnum` and `StaticStruct` for static methods, where the type //! being derived upon is either an enum or struct respectively. (Any //! argument with type Self is just grouped among the non-self //! arguments.) //! //! In the first two cases, the values from the corresponding fields in -//! all the arguments are grouped together. For `EnumNonMatchingCollapsed` -//! this isn't possible (different variants have different fields), so the -//! fields are inaccessible. (Previous versions of the deriving infrastructure -//! had a way to expand into code that could access them, at the cost of -//! generating exponential amounts of code; see issue #15375). There are no -//! fields with values in the static cases, so these are treated entirely -//! differently. +//! all the arguments are grouped together. //! //! The non-static cases have `Option<ident>` in several places associated //! with field `expr`s. This represents the name of the field it is @@ -66,7 +59,7 @@ //! //! # "`cs`" functions //! -//! The `cs_...` functions ("combine substructure) are designed to +//! The `cs_...` functions ("combine substructure") are designed to //! make life easier by providing some pre-made recipes for common //! threads; mostly calling the function being derived on all the //! arguments and then combining them back together in some way (or @@ -142,23 +135,15 @@ //! }]) //! ``` //! -//! For `C0(a)` and `C1 {x}` , +//! For the tags, //! //! ```{.text} -//! EnumNonMatchingCollapsed( -//! vec![<ident of self>, <ident of __arg_1>], -//! &[<ast::Variant for C0>, <ast::Variant for C1>], -//! &[<ident for self index value>, <ident of __arg_1 index value>]) +//! EnumTag( +//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>) //! ``` -//! -//! It is the same for when the arguments are flipped to `C1 {x}` and -//! `C0(a)`; the only difference is what the values of the identifiers -//! <ident for self index value> and <ident of __arg_1 index value> will -//! be in the generated code. -//! -//! `EnumNonMatchingCollapsed` deliberately provides far less information -//! than is generally available for a given pair of variants; see #15375 -//! for discussion. +//! Note that this setup doesn't allow for the brute-force "match every variant +//! against every other variant" approach, which is bad because it produces a +//! quadratic amount of code (see #15375). //! //! ## Static //! @@ -182,15 +167,14 @@ use std::iter; use std::vec; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, BinOpKind, EnumDef, Expr, Generics, PatKind}; +use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind}; use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; -use rustc_data_structures::map_in_place::MapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; -use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty}; +use ty::{Bounds, Path, Ref, Self_, Ty}; use crate::deriving; @@ -212,9 +196,6 @@ pub struct TraitDef<'a> { /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder` pub generics: Bounds, - /// Is it an `unsafe` trait? - pub is_unsafe: bool, - /// Can this trait be derived for unions? pub supports_unions: bool, @@ -229,23 +210,20 @@ pub struct MethodDef<'a> { /// List of generics, e.g., `R: rand::Rng` pub generics: Bounds, - /// Whether there is a self argument (outer Option) i.e., whether - /// this is a static function, and whether it is a pointer (inner - /// Option) - pub explicit_self: Option<Option<PtrTy>>, + /// Is there is a `&self` argument? If not, it is a static function. + pub explicit_self: bool, - /// Arguments other than the self argument - pub args: Vec<(Ty, Symbol)>, + /// Arguments other than the self argument. + pub nonself_args: Vec<(Ty, Symbol)>, /// Returns type pub ret_ty: Ty, pub attributes: Vec<ast::Attribute>, - // Is it an `unsafe fn`? - pub is_unsafe: bool, - /// Can we combine fieldless variants for enums into a single match arm? + /// If true, indicates that the trait operation uses the enum tag in some + /// way. pub unify_fieldless_variants: bool, pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>, @@ -255,32 +233,24 @@ pub struct MethodDef<'a> { pub struct Substructure<'a> { /// ident of self pub type_ident: Ident, - /// ident of the method - pub method_ident: Ident, - /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments - /// - /// [`Self_`]: ty::Ty::Self_ - /// [ptr]: ty::Ty::Ptr - pub self_args: &'a [P<Expr>], - /// verbatim access to any other arguments - pub nonself_args: &'a [P<Expr>], + /// Verbatim access to any non-selflike arguments, i.e. arguments that + /// don't have type `&Self`. + pub nonselflike_args: &'a [P<Expr>], pub fields: &'a SubstructureFields<'a>, } /// Summary of the relevant parts of a struct/enum field. -pub struct FieldInfo<'a> { +pub struct FieldInfo { pub span: Span, /// None for tuple structs/normal enum variants, Some for normal /// structs/struct enum variants. pub name: Option<Ident>, /// The expression corresponding to this field of `self` /// (specifically, a reference to it). - pub self_: P<Expr>, + pub self_expr: P<Expr>, /// The expressions corresponding to references to this field in - /// the other `Self` arguments. - pub other: Vec<P<Expr>>, - /// The attributes on the field - pub attrs: &'a [ast::Attribute], + /// the other selflike arguments. + pub other_selflike_exprs: Vec<P<Expr>>, } /// Fields for a static method @@ -293,22 +263,22 @@ pub enum StaticFields { /// A summary of the possible sets of fields. pub enum SubstructureFields<'a> { - Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>), + /// A non-static method with `Self` is a struct. + Struct(&'a ast::VariantData, Vec<FieldInfo>), + /// Matching variants of the enum: variant index, variant count, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. - EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>), + EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>), - /// Non-matching variants of the enum, but with all state hidden from - /// the consequent code. The first component holds `Ident`s for all of - /// the `Self` arguments; the second component is a slice of all of the - /// variants for the enum itself, and the third component is a list of - /// `Ident`s bound to the variant index values for each of the actual - /// input `Self` arguments. - EnumNonMatchingCollapsed(Vec<Ident>, &'a [ast::Variant], &'a [Ident]), + /// The tag of an enum. The first field is a `FieldInfo` for the tags, as + /// if they were fields. The second field is the expression to combine the + /// tag expression with; it will be `None` if no match is necessary. + EnumTag(FieldInfo, Option<P<Expr>>), /// A static method where `Self` is a struct. StaticStruct(&'a ast::VariantData, StaticFields), + /// A static method where `Self` is an enum. StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), } @@ -316,15 +286,7 @@ pub enum SubstructureFields<'a> { /// Combine the values of all the fields together. The last argument is /// all the fields of all the structures. pub type CombineSubstructureFunc<'a> = - Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>; - -/// Deal with non-matching enum variants. The tuple is a list of -/// identifiers (one for each `Self` argument, which could be any of the -/// variants since they have been collapsed together) and the identifiers -/// holding the variant index value for each of the `Self` arguments. The -/// last argument is all the non-`Self` args of the method being derived. -pub type EnumNonMatchCollapsedFunc<'a> = - Box<dyn FnMut(&mut ExtCtxt<'_>, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>; + Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>; pub fn combine_substructure( f: CombineSubstructureFunc<'_>, @@ -337,6 +299,55 @@ struct TypeParameter { ty: P<ast::Ty>, } +// The code snippets built up for derived code are sometimes used as blocks +// (e.g. in a function body) and sometimes used as expressions (e.g. in a match +// arm). This structure avoids committing to either form until necessary, +// avoiding the insertion of any unnecessary blocks. +// +// The statements come before the expression. +pub struct BlockOrExpr(Vec<ast::Stmt>, Option<P<Expr>>); + +impl BlockOrExpr { + pub fn new_stmts(stmts: Vec<ast::Stmt>) -> BlockOrExpr { + BlockOrExpr(stmts, None) + } + + pub fn new_expr(expr: P<Expr>) -> BlockOrExpr { + BlockOrExpr(vec![], Some(expr)) + } + + pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr { + BlockOrExpr(stmts, expr) + } + + // Converts it into a block. + fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> { + if let Some(expr) = self.1 { + self.0.push(cx.stmt_expr(expr)); + } + cx.block(span, self.0) + } + + // Converts it into an expression. + fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> { + if self.0.is_empty() { + match self.1 { + None => cx.expr_block(cx.block(span, vec![])), + Some(expr) => expr, + } + } else if self.0.len() == 1 + && let ast::StmtKind::Expr(expr) = &self.0[0].kind + && self.1.is_none() + { + // There's only a single statement expression. Pull it out. + expr.clone() + } else { + // Multiple statements and/or expressions. + cx.expr_block(self.into_block(cx, span)) + } + } +} + /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter `<T>`, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. @@ -442,7 +453,6 @@ impl<'a> TraitDef<'a> { }; let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id); - let use_temporaries = is_packed && always_copy; let newitem = match item.kind { ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def( @@ -451,10 +461,11 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - use_temporaries, + is_packed, + always_copy, ), ast::ItemKind::Enum(ref enum_def, ref generics) => { - // We ignore `use_temporaries` here, because + // We ignore `is_packed`/`always_copy` here, because // `repr(packed)` enums cause an error later on. // // This can only cause further compilation errors @@ -470,7 +481,8 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - use_temporaries, + is_packed, + always_copy, ) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -727,14 +739,12 @@ impl<'a> TraitDef<'a> { let mut a = vec![attr, unused_qual]; a.extend(self.attributes.iter().cloned()); - let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No }; - cx.item( self.span, Ident::empty(), a, ast::ItemKind::Impl(Box::new(ast::Impl { - unsafety, + unsafety: ast::Unsafe::No, polarity: ast::ImplPolarity::Positive, defaultness: ast::Defaultness::Final, constness: ast::Const::No, @@ -753,7 +763,8 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, from_scratch: bool, - use_temporaries: bool, + is_packed: bool, + always_copy: bool, ) -> P<ast::Item> { let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); @@ -762,8 +773,8 @@ impl<'a> TraitDef<'a> { .methods .iter() .map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, type_ident, generics); + let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) = + method_def.extract_arg_details(cx, self, type_ident, generics); let body = if from_scratch || method_def.is_static() { method_def.expand_static_struct_method_body( @@ -771,8 +782,7 @@ impl<'a> TraitDef<'a> { self, struct_def, type_ident, - &self_args, - &nonself_args, + &nonselflike_args, ) } else { method_def.expand_struct_method_body( @@ -780,13 +790,22 @@ impl<'a> TraitDef<'a> { self, struct_def, type_ident, - &self_args, - &nonself_args, - use_temporaries, + &selflike_args, + &nonselflike_args, + is_packed, + always_copy, ) }; - method_def.create_method(cx, self, type_ident, generics, explicit_self, tys, body) + method_def.create_method( + cx, + self, + type_ident, + generics, + explicit_self, + nonself_arg_tys, + body, + ) }) .collect(); @@ -811,8 +830,8 @@ impl<'a> TraitDef<'a> { .methods .iter() .map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, type_ident, generics); + let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) = + method_def.extract_arg_details(cx, self, type_ident, generics); let body = if from_scratch || method_def.is_static() { method_def.expand_static_enum_method_body( @@ -820,8 +839,7 @@ impl<'a> TraitDef<'a> { self, enum_def, type_ident, - &self_args, - &nonself_args, + &nonselflike_args, ) } else { method_def.expand_enum_method_body( @@ -829,12 +847,20 @@ impl<'a> TraitDef<'a> { self, enum_def, type_ident, - self_args, - &nonself_args, + selflike_args, + &nonselflike_args, ) }; - method_def.create_method(cx, self, type_ident, generics, explicit_self, tys, body) + method_def.create_method( + cx, + self, + type_ident, + generics, + explicit_self, + nonself_arg_tys, + body, + ) }) .collect(); @@ -848,18 +874,11 @@ impl<'a> MethodDef<'a> { cx: &mut ExtCtxt<'_>, trait_: &TraitDef<'_>, type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>], + nonselflike_args: &[P<Expr>], fields: &SubstructureFields<'_>, - ) -> P<Expr> { + ) -> BlockOrExpr { let span = trait_.span; - let substructure = Substructure { - type_ident, - method_ident: Ident::new(self.name, span), - self_args, - nonself_args, - fields, - }; + let substructure = Substructure { type_ident, nonselflike_args, fields }; let mut f = self.combine_substructure.borrow_mut(); let f: &mut CombineSubstructureFunc<'_> = &mut *f; f(cx, span, &substructure) @@ -876,54 +895,52 @@ impl<'a> MethodDef<'a> { } fn is_static(&self) -> bool { - self.explicit_self.is_none() + !self.explicit_self } - fn split_self_nonself_args( + // The return value includes: + // - explicit_self: The `&self` arg, if present. + // - selflike_args: Expressions for `&self` (if present) and also any other + // args with the same type (e.g. the `other` arg in `PartialEq::eq`). + // - nonselflike_args: Expressions for all the remaining args. + // - nonself_arg_tys: Additional information about all the args other than + // `&self`. + fn extract_arg_details( &self, cx: &mut ExtCtxt<'_>, trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, ) -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) { - let mut self_args = Vec::new(); - let mut nonself_args = Vec::new(); - let mut arg_tys = Vec::new(); - let mut nonstatic = false; + let mut selflike_args = Vec::new(); + let mut nonselflike_args = Vec::new(); + let mut nonself_arg_tys = Vec::new(); let span = trait_.span; - let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| { - let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr); - - self_args.push(self_expr); - nonstatic = true; - - explicit_self - }); + let explicit_self = if self.explicit_self { + let (self_expr, explicit_self) = ty::get_explicit_self(cx, span); + selflike_args.push(self_expr); + Some(explicit_self) + } else { + None + }; - for (ty, name) in self.args.iter() { + for (ty, name) in self.nonself_args.iter() { let ast_ty = ty.to_ty(cx, span, type_ident, generics); let ident = Ident::new(*name, span); - arg_tys.push((ident, ast_ty)); + nonself_arg_tys.push((ident, ast_ty)); let arg_expr = cx.expr_ident(span, ident); - match *ty { - // for static methods, just treat any Self - // arguments as a normal arg - Self_ if nonstatic => { - self_args.push(arg_expr); - } - Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => { - self_args.push(cx.expr_deref(span, arg_expr)) - } - _ => { - nonself_args.push(arg_expr); - } + match ty { + // Selflike (`&Self`) arguments only occur in non-static methods. + Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr), + Self_ => cx.span_bug(span, "`Self` in non-return position"), + _ => nonselflike_args.push(arg_expr), } } - (ast_explicit_self, self_args, nonself_args, arg_tys) + (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) } fn create_method( @@ -933,37 +950,32 @@ impl<'a> MethodDef<'a> { type_ident: Ident, generics: &Generics, explicit_self: Option<ast::ExplicitSelf>, - arg_types: Vec<(Ident, P<ast::Ty>)>, - body: P<Expr>, + nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>, + body: BlockOrExpr, ) -> P<ast::AssocItem> { let span = trait_.span; // Create the generics that aren't for `Self`. let fn_generics = self.generics.to_generics(cx, span, type_ident, generics); let args = { - let self_args = explicit_self.map(|explicit_self| { + let self_arg = explicit_self.map(|explicit_self| { let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span); ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident) }); - let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty)); - self_args.into_iter().chain(nonself_args).collect() + let nonself_args = + nonself_arg_tys.into_iter().map(|(name, ty)| cx.param(span, name, ty)); + self_arg.into_iter().chain(nonself_args).collect() }; let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); let method_ident = Ident::new(self.name, span); let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type)); - let body_block = cx.block_expr(body); - - let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No }; + let body_block = body.into_block(cx, span); let trait_lo_sp = span.shrink_to_lo(); - let sig = ast::FnSig { - header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() }, - decl: fn_decl, - span, - }; + let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span }; let defaultness = ast::Defaultness::Final; // Create the method. @@ -987,115 +999,107 @@ impl<'a> MethodDef<'a> { }) } + /// The normal case uses field access. /// ``` /// #[derive(PartialEq)] /// # struct Dummy; - /// struct A { x: i32, y: i32 } + /// struct A { x: u8, y: u8 } /// /// // equivalent to: /// impl PartialEq for A { /// fn eq(&self, other: &A) -> bool { - /// match *self { - /// A {x: ref __self_0_0, y: ref __self_0_1} => { - /// match *other { - /// A {x: ref __self_1_0, y: ref __self_1_1} => { - /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) - /// } - /// } - /// } - /// } + /// self.x == other.x && self.y == other.y /// } /// } /// ``` - /// or if A is repr(packed) - note fields are matched by-value - /// instead of by-reference. + /// But if the struct is `repr(packed)`, we can't use something like + /// `&self.x` because that might cause an unaligned ref. So for any trait + /// method that takes a reference, if the struct impls `Copy` then we use a + /// local block to force a copy: /// ``` - /// # struct A { x: i32, y: i32 } + /// # struct A { x: u8, y: u8 } /// impl PartialEq for A { /// fn eq(&self, other: &A) -> bool { - /// match *self { - /// A {x: __self_0_0, y: __self_0_1} => { - /// match other { - /// A {x: __self_1_0, y: __self_1_1} => { - /// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1) - /// } - /// } - /// } - /// } + /// // Desugars to `{ self.x }.eq(&{ other.y }) && ...` + /// { self.x } == { other.y } && { self.y } == { other.y } + /// } + /// } + /// impl Hash for A { + /// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + /// ::core::hash::Hash::hash(&{ self.x }, state); + /// ::core::hash::Hash::hash(&{ self.y }, state) /// } /// } /// ``` + /// If the struct doesn't impl `Copy`, we use let-destructuring with `ref`: + /// ``` + /// # struct A { x: u8, y: u8 } + /// impl PartialEq for A { + /// fn eq(&self, other: &A) -> bool { + /// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self; + /// let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other; + /// *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1 + /// } + /// } + /// ``` + /// This latter case only works if the fields match the alignment required + /// by the `packed(N)` attribute. (We'll get errors later on if not.) fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, trait_: &TraitDef<'b>, struct_def: &'b VariantData, type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>], - use_temporaries: bool, - ) -> P<Expr> { - let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]> + selflike_args: &[P<Expr>], + nonselflike_args: &[P<Expr>], + is_packed: bool, + always_copy: bool, + ) -> BlockOrExpr { let span = trait_.span; - let mut patterns = Vec::new(); - for i in 0..self_args.len() { - // We could use `type_ident` instead of `Self`, but in the case of a type parameter - // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343 - let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); - let (pat, ident_expr) = trait_.create_struct_pattern( + assert!(selflike_args.len() == 1 || selflike_args.len() == 2); + + let mk_body = |cx, selflike_fields| { + self.call_substructure_method( cx, - struct_path, - struct_def, - &format!("__self_{}", i), - ast::Mutability::Not, - use_temporaries, - ); - patterns.push(pat); - raw_fields.push(ident_expr); - } + trait_, + type_ident, + nonselflike_args, + &Struct(struct_def, selflike_fields), + ) + }; - // transpose raw_fields - let fields = if !raw_fields.is_empty() { - let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); - let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect(); - first_field - .map(|(span, opt_id, field, attrs)| FieldInfo { - span: span.with_ctxt(trait_.span.ctxt()), - name: opt_id, - self_: field, - other: other_fields - .iter_mut() - .map(|l| { - let (.., ex, _) = l.next().unwrap(); - ex - }) - .collect(), - attrs, - }) - .collect() + if !is_packed { + let selflike_fields = + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, false); + mk_body(cx, selflike_fields) + } else if always_copy { + let selflike_fields = + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, true); + mk_body(cx, selflike_fields) } else { - cx.span_bug(span, "no `self` parameter for method in generic `derive`") - }; + // Neither packed nor copy. Need to use ref patterns. + let prefixes: Vec<_> = + (0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect(); + let addr_of = always_copy; + let selflike_fields = + trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of); + let mut body = mk_body(cx, selflike_fields); - // body of the inner most destructuring match - let mut body = self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &Struct(struct_def, fields), - ); - - // make a series of nested matches, to destructure the - // structs. This is actually right-to-left, but it shouldn't - // matter. - for (arg_expr, pat) in iter::zip(self_args, patterns) { - body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)]) + let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); + let use_ref_pat = is_packed && !always_copy; + let patterns = + trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat); + + // Do the let-destructuring. + let mut stmts: Vec<_> = iter::zip(selflike_args, patterns) + .map(|(selflike_arg_expr, pat)| { + let selflike_arg_expr = cx.expr_deref(span, selflike_arg_expr.clone()); + cx.stmt_let_pat(span, pat, selflike_arg_expr) + }) + .collect(); + stmts.extend(std::mem::take(&mut body.0)); + BlockOrExpr(stmts, body.1) } - - body } fn expand_static_struct_method_body( @@ -1104,17 +1108,15 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, struct_def: &VariantData, type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>], - ) -> P<Expr> { + nonselflike_args: &[P<Expr>], + ) -> BlockOrExpr { let summary = trait_.summarise_struct(cx, struct_def); self.call_substructure_method( cx, trait_, type_ident, - self_args, - nonself_args, + nonselflike_args, &StaticStruct(struct_def, summary), ) } @@ -1126,243 +1128,209 @@ impl<'a> MethodDef<'a> { /// A1, /// A2(i32) /// } - /// - /// // is equivalent to - /// - /// impl PartialEq for A { + /// ``` + /// is equivalent to: + /// ``` + /// impl ::core::cmp::PartialEq for A { + /// #[inline] /// fn eq(&self, other: &A) -> bool { - /// use A::*; - /// match (&*self, &*other) { - /// (&A1, &A1) => true, - /// (&A2(ref self_0), - /// &A2(ref __arg_1_0)) => (*self_0).eq(&(*__arg_1_0)), - /// _ => { - /// let __self_vi = match *self { A1 => 0, A2(..) => 1 }; - /// let __arg_1_vi = match *other { A1 => 0, A2(..) => 1 }; - /// false + /// let __self_tag = ::core::intrinsics::discriminant_value(self); + /// let __arg1_tag = ::core::intrinsics::discriminant_value(other); + /// __self_tag == __arg1_tag && + /// match (self, other) { + /// (A::A2(__self_0), A::A2(__arg1_0)) => + /// *__self_0 == *__arg1_0, + /// _ => true, /// } - /// } /// } /// } /// ``` - /// - /// (Of course `__self_vi` and `__arg_1_vi` are unused for - /// `PartialEq`, and those subcomputations will hopefully be removed - /// as their results are unused. The point of `__self_vi` and - /// `__arg_1_vi` is for `PartialOrd`; see #15503.) + /// Creates a tag check combined with a match for a tuple of all + /// `selflike_args`, with an arm for each variant with fields, possibly an + /// arm for each fieldless variant (if `!unify_fieldless_variants` is not + /// true), and possibly a default arm. fn expand_enum_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, trait_: &TraitDef<'b>, enum_def: &'b EnumDef, type_ident: Ident, - self_args: Vec<P<Expr>>, - nonself_args: &[P<Expr>], - ) -> P<Expr> { - self.build_enum_match_tuple(cx, trait_, enum_def, type_ident, self_args, nonself_args) - } - - /// Creates a match for a tuple of all `self_args`, where either all - /// variants match, or it falls into a catch-all for when one variant - /// does not match. - - /// There are N + 1 cases because is a case for each of the N - /// variants where all of the variants match, and one catch-all for - /// when one does not match. - - /// As an optimization we generate code which checks whether all variants - /// match first which makes llvm see that C-like enums can be compiled into - /// a simple equality check (for PartialEq). - - /// The catch-all handler is provided access the variant index values - /// for each of the self-args, carried in precomputed variables. - - /// ```{.text} - /// let __self0_vi = std::intrinsics::discriminant_value(&self); - /// let __self1_vi = std::intrinsics::discriminant_value(&arg1); - /// let __self2_vi = std::intrinsics::discriminant_value(&arg2); - /// - /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { - /// match (...) { - /// (Variant1, Variant1, ...) => Body1 - /// (Variant2, Variant2, ...) => Body2, - /// ... - /// _ => ::core::intrinsics::unreachable() - /// } - /// } - /// else { - /// ... // catch-all remainder can inspect above variant index values. - /// } - /// ``` - fn build_enum_match_tuple<'b>( - &self, - cx: &mut ExtCtxt<'_>, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_ident: Ident, - mut self_args: Vec<P<Expr>>, - nonself_args: &[P<Expr>], - ) -> P<Expr> { + selflike_args: Vec<P<Expr>>, + nonselflike_args: &[P<Expr>], + ) -> BlockOrExpr { let span = trait_.span; let variants = &enum_def.variants; - let self_arg_names = iter::once("__self".to_string()) + // Traits that unify fieldless variants always use the tag(s). + let uses_tags = self.unify_fieldless_variants; + + // There is no sensible code to be generated for *any* deriving on a + // zero-variant enum. So we just generate a failing expression. + if variants.is_empty() { + return BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span))); + } + + let prefixes = iter::once("__self".to_string()) .chain( - self_args + selflike_args .iter() .enumerate() .skip(1) - .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count)), + .map(|(arg_count, _selflike_arg)| format!("__arg{}", arg_count)), ) .collect::<Vec<String>>(); - let self_arg_idents = self_arg_names - .iter() - .map(|name| Ident::from_str_and_span(name, span)) - .collect::<Vec<Ident>>(); + // Build a series of let statements mapping each selflike_arg + // to its discriminant value. + // + // e.g. for `PartialEq::eq` builds two statements: + // ``` + // let __self_tag = ::core::intrinsics::discriminant_value(self); + // let __arg1_tag = ::core::intrinsics::discriminant_value(other); + // ``` + let get_tag_pieces = |cx: &ExtCtxt<'_>| { + let tag_idents: Vec<_> = prefixes + .iter() + .map(|name| Ident::from_str_and_span(&format!("{}_tag", name), span)) + .collect(); - // The `vi_idents` will be bound, solely in the catch-all, to - // a series of let statements mapping each self_arg to an int - // value corresponding to its discriminant. - let vi_idents = self_arg_names - .iter() - .map(|name| { - let vi_suffix = format!("{}_vi", name); - Ident::from_str_and_span(&vi_suffix, span) - }) - .collect::<Vec<Ident>>(); + let mut tag_exprs: Vec<_> = tag_idents + .iter() + .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident))) + .collect(); - // Builds, via callback to call_substructure_method, the - // delegated expression that handles the catch-all case, - // using `__variants_tuple` to drive logic if necessary. - let catch_all_substructure = - EnumNonMatchingCollapsed(self_arg_idents, &variants, &vi_idents); + let self_expr = tag_exprs.remove(0); + let other_selflike_exprs = tag_exprs; + let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; - let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); + let tag_let_stmts: Vec<_> = iter::zip(&tag_idents, &selflike_args) + .map(|(&ident, selflike_arg)| { + let variant_value = deriving::call_intrinsic( + cx, + span, + sym::discriminant_value, + vec![selflike_arg.clone()], + ); + cx.stmt_let(span, false, ident, variant_value) + }) + .collect(); + + (tag_field, tag_let_stmts) + }; + + // There are some special cases involving fieldless enums where no + // match is necessary. + let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty()); + if all_fieldless { + if uses_tags && variants.len() > 1 { + // If the type is fieldless and the trait uses the tag and + // there are multiple variants, we need just an operation on + // the tag(s). + let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); + let mut tag_check = self.call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &EnumTag(tag_field, None), + ); + tag_let_stmts.append(&mut tag_check.0); + return BlockOrExpr(tag_let_stmts, tag_check.1); + } + + if variants.len() == 1 { + // If there is a single variant, we don't need an operation on + // the tag(s). Just use the most degenerate result. + return self.call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &EnumMatching(0, 1, &variants[0], Vec::new()), + ); + }; + } // These arms are of the form: // (Variant1, Variant1, ...) => Body1 // (Variant2, Variant2, ...) => Body2 // ... - // where each tuple has length = self_args.len() + // where each tuple has length = selflike_args.len() let mut match_arms: Vec<ast::Arm> = variants .iter() .enumerate() .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty())) .map(|(index, variant)| { - let mk_self_pat = |cx: &mut ExtCtxt<'_>, self_arg_name: &str| { - let (p, idents) = trait_.create_enum_variant_pattern( - cx, - type_ident, - variant, - self_arg_name, - ast::Mutability::Not, - ); - (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents) - }; - // A single arm has form (&VariantK, &VariantK, ...) => BodyK // (see "Final wrinkle" note below for why.) - let mut subpats = Vec::with_capacity(self_arg_names.len()); - let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1); - let first_self_pat_idents = { - let (p, idents) = mk_self_pat(cx, &self_arg_names[0]); - subpats.push(p); - idents - }; - for self_arg_name in &self_arg_names[1..] { - let (p, idents) = mk_self_pat(cx, &self_arg_name); - subpats.push(p); - self_pats_idents.push(idents); - } - // Here is the pat = `(&VariantK, &VariantK, ...)` - let single_pat = cx.pat_tuple(span, subpats); + let addr_of = false; // because enums can't be repr(packed) + let fields = + trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of); + + let sp = variant.span.with_ctxt(trait_.span.ctxt()); + let variant_path = cx.path(sp, vec![type_ident, variant.ident]); + let use_ref_pat = false; // because enums can't be repr(packed) + let mut subpats: Vec<_> = trait_.create_struct_patterns( + cx, + variant_path, + &variant.data, + &prefixes, + use_ref_pat, + ); + + // `(VariantK, VariantK, ...)` or just `VariantK`. + let single_pat = if subpats.len() == 1 { + subpats.pop().unwrap() + } else { + cx.pat_tuple(span, subpats) + }; // For the BodyK, we need to delegate to our caller, // passing it an EnumMatching to indicate which case // we are in. - - // All of the Self args have the same variant in these - // cases. So we transpose the info in self_pats_idents - // to gather the getter expressions together, in the - // form that EnumMatching expects. - - // The transposition is driven by walking across the - // arg fields of the variant for the first self pat. - let field_tuples = first_self_pat_idents - .into_iter() - .enumerate() - // For each arg field of self, pull out its getter expr ... - .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| { - // ... but FieldInfo also wants getter expr - // for matching other arguments of Self type; - // so walk across the *other* self_pats_idents - // and pull out getter for same field in each - // of them (using `field_index` tracked above). - // That is the heart of the transposition. - let others = self_pats_idents - .iter() - .map(|fields| { - let (_, _opt_ident, ref other_getter_expr, _) = fields[field_index]; - - // All Self args have same variant, so - // opt_idents are the same. (Assert - // here to make it self-evident that - // it is okay to ignore `_opt_ident`.) - assert!(opt_ident == _opt_ident); - - other_getter_expr.clone() - }) - .collect::<Vec<P<Expr>>>(); - - FieldInfo { - span, - name: opt_ident, - self_: self_getter_expr, - other: others, - attrs, - } - }) - .collect::<Vec<FieldInfo<'_>>>(); - + // // Now, for some given VariantK, we have built up // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, variants.len(), variant, field_tuples); - let arm_expr = self.call_substructure_method( - cx, - trait_, - type_ident, - &self_args[..], - nonself_args, - &substructure, - ); + let substructure = EnumMatching(index, variants.len(), variant, fields); + let arm_expr = self + .call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &substructure, + ) + .into_expr(cx, span); cx.arm(span, single_pat, arm_expr) }) .collect(); + // Add a default arm to the match, if necessary. + let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty()); let default = match first_fieldless { Some(v) if self.unify_fieldless_variants => { - // We need a default case that handles the fieldless variants. - // The index and actual variant aren't meaningful in this case, - // so just use whatever - let substructure = EnumMatching(0, variants.len(), v, Vec::new()); - Some(self.call_substructure_method( - cx, - trait_, - type_ident, - &self_args[..], - nonself_args, - &substructure, - )) + // We need a default case that handles all the fieldless + // variants. The index and actual variant aren't meaningful in + // this case, so just use dummy values. + Some( + self.call_substructure_method( + cx, + trait_, + type_ident, + nonselflike_args, + &EnumMatching(0, variants.len(), v, Vec::new()), + ) + .into_expr(cx, span), + ) } - _ if variants.len() > 1 && self_args.len() > 1 => { - // Since we know that all the arguments will match if we reach + _ if variants.len() > 1 && selflike_args.len() > 1 => { + // Because we know that all the arguments will match if we reach // the match expression we add the unreachable intrinsics as the - // result of the catch all which should help llvm in optimizing it + // result of the default which should help llvm in optimizing it. Some(deriving::call_unreachable(cx, span)) } _ => None, @@ -1371,154 +1339,41 @@ impl<'a> MethodDef<'a> { match_arms.push(cx.arm(span, cx.pat_wild(span), arm)); } - // We will usually need the catch-all after matching the - // tuples `(VariantK, VariantK, ...)` for each VariantK of the - // enum. But: - // - // * when there is only one Self arg, the arms above suffice - // (and the deriving we call back into may not be prepared to - // handle EnumNonMatchCollapsed), and, - // - // * when the enum has only one variant, the single arm that - // is already present always suffices. - // - // * In either of the two cases above, if we *did* add a - // catch-all `_` match, it would trigger the - // unreachable-pattern error. - // - if variants.len() > 1 && self_args.len() > 1 { - // Build a series of let statements mapping each self_arg - // to its discriminant value. - // - // i.e., for `enum E<T> { A, B(1), C(T, T) }`, and a deriving - // with three Self args, builds three statements: - // - // ``` - // let __self0_vi = std::intrinsics::discriminant_value(&self); - // let __self1_vi = std::intrinsics::discriminant_value(&arg1); - // let __self2_vi = std::intrinsics::discriminant_value(&arg2); - // ``` - let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1); - - // We also build an expression which checks whether all discriminants are equal - // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... - let mut discriminant_test = cx.expr_bool(span, true); - - let mut first_ident = None; - for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) { - let self_addr = cx.expr_addr_of(span, self_arg.clone()); - let variant_value = - deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]); - let let_stmt = cx.stmt_let(span, false, ident, variant_value); - index_let_stmts.push(let_stmt); - - match first_ident { - Some(first) => { - let first_expr = cx.expr_ident(span, first); - let id = cx.expr_ident(span, ident); - let test = cx.expr_binary(span, BinOpKind::Eq, first_expr, id); - discriminant_test = - cx.expr_binary(span, BinOpKind::And, discriminant_test, test) - } - None => { - first_ident = Some(ident); - } - } - } + // Create a match expression with one arm per discriminant plus + // possibly a default arm, e.g.: + // match (self, other) { + // (Variant1, Variant1, ...) => Body1 + // (Variant2, Variant2, ...) => Body2, + // ... + // _ => ::core::intrinsics::unreachable() + // } + let get_match_expr = |mut selflike_args: Vec<P<Expr>>| { + let match_arg = if selflike_args.len() == 1 { + selflike_args.pop().unwrap() + } else { + cx.expr(span, ast::ExprKind::Tup(selflike_args)) + }; + cx.expr_match(span, match_arg, match_arms) + }; + + // If the trait uses the tag and there are multiple variants, we need + // to add a tag check operation before the match. Otherwise, the match + // is enough. + if uses_tags && variants.len() > 1 { + let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx); - let arm_expr = self.call_substructure_method( + // Combine a tag check with the match. + let mut tag_check_plus_match = self.call_substructure_method( cx, trait_, type_ident, - &self_args[..], - nonself_args, - &catch_all_substructure, + nonselflike_args, + &EnumTag(tag_field, Some(get_match_expr(selflike_args))), ); - - // Final wrinkle: the self_args are expressions that deref - // down to desired places, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg)); - let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args)); - - // Lastly we create an expression which branches on all discriminants being equal - // if discriminant_test { - // match (...) { - // (Variant1, Variant1, ...) => Body1 - // (Variant2, Variant2, ...) => Body2, - // ... - // _ => ::core::intrinsics::unreachable() - // } - // } - // else { - // <delegated expression referring to __self0_vi, et al.> - // } - let all_match = cx.expr_match(span, match_arg, match_arms); - let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr)); - index_let_stmts.push(cx.stmt_expr(arm_expr)); - cx.expr_block(cx.block(span, index_let_stmts)) - } else if variants.is_empty() { - // As an additional wrinkle, For a zero-variant enum A, - // currently the compiler - // will accept `fn (a: &Self) { match *a { } }` - // but rejects `fn (a: &Self) { match (&*a,) { } }` - // as well as `fn (a: &Self) { match ( *a,) { } }` - // - // This means that the strategy of building up a tuple of - // all Self arguments fails when Self is a zero variant - // enum: rustc rejects the expanded program, even though - // the actual code tends to be impossible to execute (at - // least safely), according to the type system. - // - // The most expedient fix for this is to just let the - // code fall through to the catch-all. But even this is - // error-prone, since the catch-all as defined above would - // generate code like this: - // - // _ => { let __self0 = match *self { }; - // let __self1 = match *__arg_0 { }; - // <catch-all-expr> } - // - // Which is yields bindings for variables which type - // inference cannot resolve to unique types. - // - // One option to the above might be to add explicit type - // annotations. But the *only* reason to go down that path - // would be to try to make the expanded output consistent - // with the case when the number of enum variants >= 1. - // - // That just isn't worth it. In fact, trying to generate - // sensible code for *any* deriving on a zero-variant enum - // does not make sense. But at the same time, for now, we - // do not want to cause a compile failure just because the - // user happened to attach a deriving to their - // zero-variant enum. - // - // Instead, just generate a failing expression for the - // zero variant case, skipping matches and also skipping - // delegating back to the end user code entirely. - // - // (See also #4499 and #12609; note that some of the - // discussions there influence what choice we make here; - // e.g., if we feature-gate `match x { ... }` when x refers - // to an uninhabited type (e.g., a zero-variant enum or a - // type holding such an enum), but do not feature-gate - // zero-variant enums themselves, then attempting to - // derive Debug on such a type could here generate code - // that needs the feature gate enabled.) - - deriving::call_unreachable(cx, span) + tag_let_stmts.append(&mut tag_check_plus_match.0); + BlockOrExpr(tag_let_stmts, tag_check_plus_match.1) } else { - // Final wrinkle: the self_args are expressions that deref - // down to desired places, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg)); - let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args)); - cx.expr_match(span, match_arg, match_arms) + BlockOrExpr(vec![], Some(get_match_expr(selflike_args))) } } @@ -1528,9 +1383,8 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, enum_def: &EnumDef, type_ident: Ident, - self_args: &[P<Expr>], - nonself_args: &[P<Expr>], - ) -> P<Expr> { + nonselflike_args: &[P<Expr>], + ) -> BlockOrExpr { let summary = enum_def .variants .iter() @@ -1544,8 +1398,7 @@ impl<'a> MethodDef<'a> { cx, trait_, type_ident, - self_args, - nonself_args, + nonselflike_args, &StaticEnum(enum_def, summary), ) } @@ -1578,203 +1431,218 @@ impl<'a> TraitDef<'a> { } } - fn create_subpatterns( + fn create_struct_patterns( &self, cx: &mut ExtCtxt<'_>, - field_paths: Vec<Ident>, - mutbl: ast::Mutability, - use_temporaries: bool, + struct_path: ast::Path, + struct_def: &'a VariantData, + prefixes: &[String], + use_ref_pat: bool, ) -> Vec<P<ast::Pat>> { - field_paths + prefixes .iter() - .map(|path| { - let binding_mode = if use_temporaries { - ast::BindingMode::ByValue(ast::Mutability::Not) - } else { - ast::BindingMode::ByRef(mutbl) - }; - cx.pat(path.span, PatKind::Ident(binding_mode, *path, None)) + .map(|prefix| { + let pieces_iter = + struct_def.fields().iter().enumerate().map(|(i, struct_field)| { + let sp = struct_field.span.with_ctxt(self.span.ctxt()); + let binding_mode = if use_ref_pat { + ast::BindingMode::ByRef(ast::Mutability::Not) + } else { + ast::BindingMode::ByValue(ast::Mutability::Not) + }; + let ident = self.mk_pattern_ident(prefix, i); + let path = ident.with_span_pos(sp); + ( + sp, + struct_field.ident, + cx.pat(path.span, PatKind::Ident(binding_mode, path, None)), + ) + }); + + let struct_path = struct_path.clone(); + match *struct_def { + VariantData::Struct(..) => { + let field_pats = pieces_iter + .map(|(sp, ident, pat)| { + if ident.is_none() { + cx.span_bug( + sp, + "a braced struct with unnamed fields in `derive`", + ); + } + ast::PatField { + ident: ident.unwrap(), + is_shorthand: false, + attrs: ast::AttrVec::new(), + id: ast::DUMMY_NODE_ID, + span: pat.span.with_ctxt(self.span.ctxt()), + pat, + is_placeholder: false, + } + }) + .collect(); + cx.pat_struct(self.span, struct_path, field_pats) + } + VariantData::Tuple(..) => { + let subpats = pieces_iter.map(|(_, _, subpat)| subpat).collect(); + cx.pat_tuple_struct(self.span, struct_path, subpats) + } + VariantData::Unit(..) => cx.pat_path(self.span, struct_path), + } + }) + .collect() + } + + fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo> + where + F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>, + { + struct_def + .fields() + .iter() + .enumerate() + .map(|(i, struct_field)| { + // For this field, get an expr for each selflike_arg. E.g. for + // `PartialEq::eq`, one for each of `&self` and `other`. + let sp = struct_field.span.with_ctxt(self.span.ctxt()); + let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp); + let self_expr = exprs.remove(0); + let other_selflike_exprs = exprs; + FieldInfo { + span: sp.with_ctxt(self.span.ctxt()), + name: struct_field.ident, + self_expr, + other_selflike_exprs, + } }) .collect() } - fn create_struct_pattern( + fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident { + Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span) + } + + fn create_struct_pattern_fields( &self, cx: &mut ExtCtxt<'_>, - struct_path: ast::Path, struct_def: &'a VariantData, - prefix: &str, - mutbl: ast::Mutability, - use_temporaries: bool, - ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) { - let mut paths = Vec::new(); - let mut ident_exprs = Vec::new(); - for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let ident = Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span); - paths.push(ident.with_span_pos(sp)); - let val = cx.expr_path(cx.path_ident(sp, ident)); - let val = if use_temporaries { val } else { cx.expr_deref(sp, val) }; - let val = cx.expr(sp, ast::ExprKind::Paren(val)); - - ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..])); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries); - let pattern = match *struct_def { - VariantData::Struct(..) => { - let field_pats = iter::zip(subpats, &ident_exprs) - .map(|(pat, &(sp, ident, ..))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } - ast::PatField { - ident: ident.unwrap(), - is_shorthand: false, - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - span: pat.span.with_ctxt(self.span.ctxt()), - pat, - is_placeholder: false, - } - }) - .collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } - VariantData::Tuple(..) => cx.pat_tuple_struct(self.span, struct_path, subpats), - VariantData::Unit(..) => cx.pat_path(self.span, struct_path), - }; - - (pattern, ident_exprs) + prefixes: &[String], + addr_of: bool, + ) -> Vec<FieldInfo> { + self.create_fields(struct_def, |i, _struct_field, sp| { + prefixes + .iter() + .map(|prefix| { + let ident = self.mk_pattern_ident(prefix, i); + let expr = cx.expr_path(cx.path_ident(sp, ident)); + if addr_of { cx.expr_addr_of(sp, expr) } else { expr } + }) + .collect() + }) } - fn create_enum_variant_pattern( + fn create_struct_field_access_fields( &self, cx: &mut ExtCtxt<'_>, - enum_ident: Ident, - variant: &'a ast::Variant, - prefix: &str, - mutbl: ast::Mutability, - ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) { - let sp = variant.span.with_ctxt(self.span.ctxt()); - let variant_path = cx.path(sp, vec![enum_ident, variant.ident]); - let use_temporaries = false; // enums can't be repr(packed) - self.create_struct_pattern(cx, variant_path, &variant.data, prefix, mutbl, use_temporaries) + selflike_args: &[P<Expr>], + struct_def: &'a VariantData, + copy: bool, + ) -> Vec<FieldInfo> { + self.create_fields(struct_def, |i, struct_field, sp| { + selflike_args + .iter() + .map(|selflike_arg| { + // Note: we must use `struct_field.span` rather than `sp` in the + // `unwrap_or_else` case otherwise the hygiene is wrong and we get + // "field `0` of struct `Point` is private" errors on tuple + // structs. + let mut field_expr = cx.expr( + sp, + ast::ExprKind::Field( + selflike_arg.clone(), + struct_field.ident.unwrap_or_else(|| { + Ident::from_str_and_span(&i.to_string(), struct_field.span) + }), + ), + ); + if copy { + field_expr = cx.expr_block( + cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), + ); + } + cx.expr_addr_of(sp, field_expr) + }) + .collect() + }) } } -// helpful premade recipes +/// The function passed to `cs_fold` is called repeatedly with a value of this +/// type. It describes one part of the code generation. The result is always an +/// expression. +pub enum CsFold<'a> { + /// The basic case: a field expression for one or more selflike args. E.g. + /// for `PartialEq::eq` this is something like `self.x == other.x`. + Single(&'a FieldInfo), -pub fn cs_fold_fields<'a, F>( - use_foldl: bool, - mut f: F, - base: P<Expr>, - cx: &mut ExtCtxt<'_>, - all_fields: &[FieldInfo<'a>], -) -> P<Expr> -where - F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>, -{ - if use_foldl { - all_fields - .iter() - .fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other)) - } else { - all_fields - .iter() - .rev() - .fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other)) - } -} - -pub fn cs_fold_enumnonmatch( - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>, - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substructure: &Substructure<'_>, -) -> P<Expr> { - match *substructure.fields { - EnumNonMatchingCollapsed(ref all_args, _, tuple) => { - enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), substructure.nonself_args) - } - _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"), - } -} + /// The combination of two field expressions. E.g. for `PartialEq::eq` this + /// is something like `<field1 equality> && <field2 equality>`. + Combine(Span, P<Expr>, P<Expr>), -pub fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> { - cx.span_bug(trait_span, "static function in `derive`") + // The fallback case for a struct or enum variant with no fields. + Fieldless, } -/// Fold the fields. `use_foldl` controls whether this is done -/// left-to-right (`true`) or right-to-left (`false`). +/// Folds over fields, combining the expressions for each field in a sequence. +/// Statics may not be folded over. pub fn cs_fold<F>( use_foldl: bool, - f: F, - base: P<Expr>, - enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>, cx: &mut ExtCtxt<'_>, trait_span: Span, substructure: &Substructure<'_>, + mut f: F, ) -> P<Expr> where - F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>, + F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>, { - match *substructure.fields { - EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { - cs_fold_fields(use_foldl, f, base, cx, all_fields) - } - EnumNonMatchingCollapsed(..) => { - cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) - } - StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span), - } -} + match substructure.fields { + EnumMatching(.., all_fields) | Struct(_, all_fields) => { + if all_fields.is_empty() { + return f(cx, CsFold::Fieldless); + } -/// Function to fold over fields, with three cases, to generate more efficient and concise code. -/// When the `substructure` has grouped fields, there are two cases: -/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`). -/// One or more fields: call the base case function on the first value (which depends on -/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the -/// fields. -/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f` -/// is returned. Statics may not be folded over. -/// See `cs_op` in `partial_ord.rs` for a model example. -pub fn cs_fold1<F, B>( - use_foldl: bool, - f: F, - mut b: B, - enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>, - cx: &mut ExtCtxt<'_>, - trait_span: Span, - substructure: &Substructure<'_>, -) -> P<Expr> -where - F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>, - B: FnMut(&mut ExtCtxt<'_>, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>, -{ - match *substructure.fields { - EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { - let (base, all_fields) = match (all_fields.is_empty(), use_foldl) { - (false, true) => { - let field = &all_fields[0]; - let args = (field.span, field.self_.clone(), &field.other[..]); - (b(cx, Some(args)), &all_fields[1..]) - } - (false, false) => { - let idx = all_fields.len() - 1; - let field = &all_fields[idx]; - let args = (field.span, field.self_.clone(), &field.other[..]); - (b(cx, Some(args)), &all_fields[..idx]) - } - (true, _) => (b(cx, None), &all_fields[..]), + let (base_field, rest) = if use_foldl { + all_fields.split_first().unwrap() + } else { + all_fields.split_last().unwrap() }; - cs_fold_fields(use_foldl, f, base, cx, all_fields) + let base_expr = f(cx, CsFold::Single(base_field)); + + let op = |old, field: &FieldInfo| { + let new = f(cx, CsFold::Single(field)); + f(cx, CsFold::Combine(field.span, old, new)) + }; + + if use_foldl { + rest.iter().fold(base_expr, op) + } else { + rest.iter().rfold(base_expr, op) + } } - EnumNonMatchingCollapsed(..) => { - cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) + EnumTag(tag_field, match_expr) => { + let tag_check_expr = f(cx, CsFold::Single(tag_field)); + if let Some(match_expr) = match_expr { + if use_foldl { + f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone())) + } else { + f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr)) + } + } else { + tag_check_expr + } } - StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span), + StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 7a41800325084..4d46f7cd48a51 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -1,7 +1,6 @@ //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use //! when specifying impls to be derived. -pub use PtrTy::*; pub use Ty::*; use rustc_ast::ptr::P; @@ -11,22 +10,11 @@ use rustc_span::source_map::{respan, DUMMY_SP}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; -/// The types of pointers -#[derive(Clone)] -pub enum PtrTy { - /// &'lifetime mut - Borrowed(Option<Ident>, ast::Mutability), - /// *mut - #[allow(dead_code)] - Raw(ast::Mutability), -} - /// A path, e.g., `::std::option::Option::<i32>` (global). Has support -/// for type parameters and a lifetime. +/// for type parameters. #[derive(Clone)] pub struct Path { path: Vec<Symbol>, - lifetime: Option<Ident>, params: Vec<Box<Ty>>, kind: PathKind, } @@ -40,18 +28,13 @@ pub enum PathKind { impl Path { pub fn new(path: Vec<Symbol>) -> Path { - Path::new_(path, None, Vec::new(), PathKind::Std) + Path::new_(path, Vec::new(), PathKind::Std) } pub fn new_local(path: Symbol) -> Path { - Path::new_(vec![path], None, Vec::new(), PathKind::Local) + Path::new_(vec![path], Vec::new(), PathKind::Local) } - pub fn new_( - path: Vec<Symbol>, - lifetime: Option<Ident>, - params: Vec<Box<Ty>>, - kind: PathKind, - ) -> Path { - Path { path, lifetime, params, kind } + pub fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path { + Path { path, params, kind } } pub fn to_ty( @@ -71,10 +54,8 @@ impl Path { self_generics: &Generics, ) -> ast::Path { let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect(); - let lt = mk_lifetimes(cx, span, &self.lifetime); let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)); - let params = - lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect(); + let params = tys.map(GenericArg::Type).collect(); match self.kind { PathKind::Global => cx.path_all(span, true, idents, params), @@ -92,40 +73,17 @@ impl Path { #[derive(Clone)] pub enum Ty { Self_, - /// &/Box/ Ty - Ptr(Box<Ty>, PtrTy), + /// A reference. + Ref(Box<Ty>, ast::Mutability), /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type /// parameter, and things like `i32` - Literal(Path), - /// includes unit - Tuple(Vec<Ty>), -} - -pub fn borrowed_ptrty() -> PtrTy { - Borrowed(None, ast::Mutability::Not) -} -pub fn borrowed(ty: Box<Ty>) -> Ty { - Ptr(ty, borrowed_ptrty()) -} - -pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> { - Some(Some(borrowed_ptrty())) -} - -pub fn borrowed_self() -> Ty { - borrowed(Box::new(Self_)) + Path(Path), + /// For () return types. + Unit, } -pub fn nil_ty() -> Ty { - Tuple(Vec::new()) -} - -fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> { - lt.map(|ident| cx.lifetime(span, ident)) -} - -fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> { - mk_lifetime(cx, span, lt).into_iter().collect() +pub fn self_ref() -> Ty { + Ref(Box::new(Self_), ast::Mutability::Not) } impl Ty { @@ -136,23 +94,15 @@ impl Ty { self_ty: Ident, self_generics: &Generics, ) -> P<ast::Ty> { - match *self { - Ptr(ref ty, ref ptr) => { + match self { + Ref(ty, mutbl) => { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = mk_lifetime(cx, span, lt); - cx.ty_rptr(span, raw_ty, lt, mutbl) - } - Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl), - } + cx.ty_rptr(span, raw_ty, None, *mutbl) } - Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics), + Path(p) => p.to_ty(cx, span, self_ty, self_generics), Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), - Tuple(ref fields) => { - let ty = ast::TyKind::Tup( - fields.iter().map(|f| f.to_ty(cx, span, self_ty, self_generics)).collect(), - ); + Unit => { + let ty = ast::TyKind::Tup(vec![]); cx.ty(span, ty) } } @@ -185,9 +135,9 @@ impl Ty { cx.path_all(span, false, vec![self_ty], params) } - Literal(ref p) => p.to_path(cx, span, self_ty, generics), - Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"), - Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"), + Path(ref p) => p.to_path(cx, span, self_ty, generics), + Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"), + Unit => cx.span_bug(span, "unit in a path in generic `derive`"), } } } @@ -245,28 +195,9 @@ impl Bounds { } } -pub fn get_explicit_self( - cx: &ExtCtxt<'_>, - span: Span, - self_ptr: &Option<PtrTy>, -) -> (P<Expr>, ast::ExplicitSelf) { - // this constructs a fresh `self` path +pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) { + // This constructs a fresh `self` path. let self_path = cx.expr_self(span); - match *self_ptr { - None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Not))), - Some(ref ptr) => { - let self_ty = respan( - span, - match *ptr { - Borrowed(ref lt, mutbl) => { - let lt = lt.map(|s| cx.lifetime(span, s)); - SelfKind::Region(lt, mutbl) - } - Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition"), - }, - ); - let self_expr = cx.expr_deref(span, self_path); - (self_expr, self_ty) - } - } + let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); + (self_path, self_ty) } diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f1d46f03bad8f..32ae3d3447896 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,9 +1,8 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; -use crate::deriving::{self, path_std, pathvec_std}; +use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::ptr::P; -use rustc_ast::{Expr, MetaItem, Mutability}; +use rustc_ast::{MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -15,7 +14,7 @@ pub fn expand_deriving_hash( item: &Annotatable, push: &mut dyn FnMut(Annotatable), ) { - let path = Path::new_(pathvec_std!(hash::Hash), None, vec![], PathKind::Std); + let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std); let typaram = sym::__H; @@ -26,16 +25,14 @@ pub fn expand_deriving_hash( path, additional_bounds: Vec::new(), generics: Bounds::empty(), - is_unsafe: false, supports_unions: false, methods: vec![MethodDef { name: sym::hash, generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] }, - explicit_self: borrowed_explicit_self(), - args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), sym::state)], - ret_ty: nil_ty(), + explicit_self: true, + nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)], + ret_ty: Unit, attributes: vec![], - is_unsafe: false, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { hash_substructure(a, b, c) @@ -47,42 +44,37 @@ pub fn expand_deriving_hash( hash_trait_def.expand(cx, mitem, item, push); } -fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> { - let [state_expr] = substr.nonself_args else { +fn hash_substructure( + cx: &mut ExtCtxt<'_>, + trait_span: Span, + substr: &Substructure<'_>, +) -> BlockOrExpr { + let [state_expr] = substr.nonselflike_args else { cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"); }; - let call_hash = |span, thing_expr| { + let call_hash = |span, expr| { let hash_path = { let strs = cx.std_path(&[sym::hash, sym::Hash, sym::hash]); cx.expr_path(cx.path_global(span, strs)) }; - let ref_thing = cx.expr_addr_of(span, thing_expr); - let expr = cx.expr_call(span, hash_path, vec![ref_thing, state_expr.clone()]); + let expr = cx.expr_call(span, hash_path, vec![expr, state_expr.clone()]); cx.stmt_expr(expr) }; - let mut stmts = Vec::new(); - - let fields = match substr.fields { - Struct(_, fs) | EnumMatching(_, 1, .., fs) => fs, - EnumMatching(.., fs) => { - let variant_value = deriving::call_intrinsic( - cx, - trait_span, - sym::discriminant_value, - vec![cx.expr_self(trait_span)], - ); - - stmts.push(call_hash(trait_span, variant_value)); - fs + let (stmts, match_expr) = match substr.fields { + Struct(_, fields) | EnumMatching(.., fields) => { + let stmts = + fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect(); + (stmts, None) + } + EnumTag(tag_field, match_expr) => { + assert!(tag_field.other_selflike_exprs.is_empty()); + let stmts = vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; + (stmts, match_expr.clone()) } _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"), }; - stmts.extend( - fields.iter().map(|FieldInfo { ref self_, span, .. }| call_hash(*span, self_.clone())), - ); - - cx.expr_block(cx.block(trait_span, stmts)) + BlockOrExpr::new_mixed(stmts, match_expr) } diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index c678c8cbd159e..c1ca089da221f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::{Impl, ItemKind, MetaItem}; +use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -193,3 +193,16 @@ fn inject_impl_of_structural_trait( push(Annotatable::Item(newitem)); } + +fn assert_ty_bounds( + cx: &mut ExtCtxt<'_>, + stmts: &mut Vec<ast::Stmt>, + ty: P<ast::Ty>, + span: Span, + assert_path: &[Symbol], +) { + // Generate statement `let _: assert_path<ty>;`. + let span = cx.with_def_site_ctxt(span); + let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]); + stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 10348c4967c7c..3b7e2102ffa9b 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -14,6 +14,9 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{InnerSpan, Span}; use smallvec::SmallVec; +use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; +use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; +use rustc_parse_format::Count; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -57,7 +60,7 @@ struct Context<'a, 'b> { /// Unique format specs seen for each argument. arg_unique_types: Vec<Vec<ArgumentType>>, /// Map from named arguments to their resolved indices. - names: FxHashMap<Symbol, usize>, + names: FxHashMap<Symbol, (usize, Span)>, /// The latest consecutive literal strings, or empty if there weren't any. literal: String, @@ -130,9 +133,9 @@ fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream, -) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>)> { +) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> { let mut args = Vec::<P<ast::Expr>>::new(); - let mut names = FxHashMap::<Symbol, usize>::default(); + let mut names = FxHashMap::<Symbol, (usize, Span)>::default(); let mut p = ecx.new_parser_from_tts(tts); @@ -197,7 +200,7 @@ fn parse_args<'a>( p.bump(); p.expect(&token::Eq)?; let e = p.parse_expr()?; - if let Some(prev) = names.get(&ident.name) { + if let Some((prev, _)) = names.get(&ident.name) { ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) .span_label(args[*prev].span, "previously here") .span_label(e.span, "duplicate argument") @@ -210,7 +213,7 @@ fn parse_args<'a>( // if the input is valid, we can simply append to the positional // args. And remember the names. let slot = args.len(); - names.insert(ident.name, slot); + names.insert(ident.name, (slot, ident.span)); args.push(e); } _ => { @@ -222,7 +225,7 @@ fn parse_args<'a>( ); err.span_label(e.span, "positional arguments must be before named arguments"); for pos in names.values() { - err.span_label(args[*pos].span, "named argument"); + err.span_label(args[pos.0].span, "named argument"); } err.emit(); } @@ -242,7 +245,8 @@ impl<'a, 'b> Context<'a, 'b> { fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) { // NOTE: the `unwrap_or` branch is needed in case of invalid format // arguments, e.g., `format_args!("{foo}")`. - let lookup = |s: &str| *self.names.get(&Symbol::intern(s)).unwrap_or(&0); + let lookup = + |s: &str| self.names.get(&Symbol::intern(s)).unwrap_or(&(0, Span::default())).0; match *p { parse::String(_) => {} @@ -548,7 +552,7 @@ impl<'a, 'b> Context<'a, 'b> { match self.names.get(&name) { Some(&idx) => { // Treat as positional arg. - self.verify_arg_type(Capture(idx), ty) + self.verify_arg_type(Capture(idx.0), ty) } None => { // For the moment capturing variables from format strings expanded from macros is @@ -565,7 +569,7 @@ impl<'a, 'b> Context<'a, 'b> { }; self.num_captured_args += 1; self.args.push(self.ecx.expr_ident(span, Ident::new(name, span))); - self.names.insert(name, idx); + self.names.insert(name, (idx, span)); self.verify_arg_type(Capture(idx), ty) } else { let msg = format!("there is no argument named `{}`", name); @@ -776,7 +780,7 @@ impl<'a, 'b> Context<'a, 'b> { // First, build up the static array which will become our precompiled // format "string" - let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces); + let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces); // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments // constructor. In general the expressions in this slice might be @@ -849,7 +853,7 @@ impl<'a, 'b> Context<'a, 'b> { fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg)); } - let args_array = self.ecx.expr_vec(self.macsp, fmt_args); + let args_array = self.ecx.expr_array(self.macsp, fmt_args); let args_slice = self.ecx.expr_addr_of( self.macsp, if no_need_for_match { @@ -879,7 +883,7 @@ impl<'a, 'b> Context<'a, 'b> { } else { // Build up the static array which will store our precompiled // nonstandard placeholders, if there are any. - let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces); + let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces); let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]); let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new()); @@ -967,6 +971,48 @@ pub fn expand_format_args_nl<'cx>( expand_format_args_impl(ecx, sp, tts, true) } +fn lint_named_arguments_used_positionally( + names: FxHashMap<Symbol, (usize, Span)>, + cx: &mut Context<'_, '_>, + unverified_pieces: Vec<parse::Piece<'_>>, +) { + let mut used_argument_names = FxHashSet::<&str>::default(); + for piece in unverified_pieces { + if let rustc_parse_format::Piece::NextArgument(a) = piece { + match a.position { + rustc_parse_format::Position::ArgumentNamed(arg_name, _) => { + used_argument_names.insert(arg_name); + } + _ => {} + }; + if let Count::CountIsName(s, _) = a.format.width { + used_argument_names.insert(s); + } + if let Count::CountIsName(s, _) = a.format.precision { + used_argument_names.insert(s); + } + } + } + + for (symbol, (index, span)) in names { + if !used_argument_names.contains(symbol.as_str()) { + let msg = format!("named argument `{}` is not used by name", symbol.as_str()); + let arg_span = cx.arg_spans.get(index).copied(); + cx.ecx.buffered_early_lint.push(BufferedEarlyLint { + span: MultiSpan::from_span(span), + msg: msg.clone(), + node_id: ast::CRATE_NODE_ID, + lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), + diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( + arg_span, + span, + symbol.to_string(), + ), + }); + } + } +} + /// Take the various parts of `format_args!(efmt, args..., name=names...)` /// and construct the appropriate formatting expression. pub fn expand_preparsed_format_args( @@ -974,7 +1020,7 @@ pub fn expand_preparsed_format_args( sp: Span, efmt: P<ast::Expr>, args: Vec<P<ast::Expr>>, - names: FxHashMap<Symbol, usize>, + names: FxHashMap<Symbol, (usize, Span)>, append_newline: bool, ) -> P<ast::Expr> { // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because @@ -1073,7 +1119,12 @@ pub fn expand_preparsed_format_args( .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .collect(); - let named_pos: FxHashSet<usize> = names.values().cloned().collect(); + let named_pos: FxHashSet<usize> = names.values().cloned().map(|(i, _)| i).collect(); + + // Clone `names` because `names` in Context get updated by verify_piece, which includes usages + // of the names of named arguments, resulting in incorrect errors if a name argument is used + // but not declared, such as: `println!("x = {x}");` + let named_arguments = names.clone(); let mut cx = Context { ecx, @@ -1101,9 +1152,11 @@ pub fn expand_preparsed_format_args( is_literal: parser.is_literal, }; - // This needs to happen *after* the Parser has consumed all pieces to create all the spans + // This needs to happen *after* the Parser has consumed all pieces to create all the spans. + // unverified_pieces is used later to check named argument names are used, so clone each piece. let pieces = unverified_pieces - .into_iter() + .iter() + .cloned() .map(|mut piece| { cx.verify_piece(&piece); cx.resolve_name_inplace(&mut piece); @@ -1265,6 +1318,11 @@ pub fn expand_preparsed_format_args( } diag.emit(); + } else if cx.invalid_refs.is_empty() && !named_arguments.is_empty() { + // Only check for unused named argument names if there are no other errors to avoid causing + // too much noise in output errors, such as when a named argument is entirely unused. + // We also only need to perform this check if there are actually named arguments. + lint_named_arguments_used_positionally(named_arguments, &mut cx, unverified_pieces); } cx.into_expr() diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 11565ba72d755..0192f3c8ca4f2 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -8,7 +8,7 @@ #![feature(decl_macro)] #![feature(if_let_guard)] #![feature(is_sorted)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 03159d4395066..5cfda33491d5b 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -317,7 +317,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { proc_macro_ty_method_path(cx, custom_derive), vec![ cx.expr_str(span, cd.trait_name), - cx.expr_vec_slice( + cx.expr_array_ref( span, cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<Vec<_>>(), ), @@ -362,7 +362,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { ast::Mutability::Not, ), ast::Mutability::Not, - cx.expr_vec_slice(span, decls), + cx.expr_array_ref(span, decls), ) .map(|mut i| { let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a08495f7671b0..0ebe29df95f20 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -51,7 +51,7 @@ pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast let test_runner = get_test_runner(sess, span_diagnostic, &krate); if sess.opts.test { - let panic_strategy = match (panic_strategy, sess.opts.debugging_opts.panic_abort_tests) { + let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { (PanicStrategy::Abort, true) => PanicStrategy::Abort, (PanicStrategy::Abort, false) => { if panic_strategy == platform_panic_strategy { @@ -352,7 +352,7 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> { debug!("building test vector from {} tests", cx.test_cases.len()); let ecx = &cx.ext_cx; - ecx.expr_vec_slice( + ecx.expr_array_ref( sp, cx.test_cases .iter() diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 7b8e43b639f99..da18ac7eacbfc 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "target-lexicon" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 18d7f41cf408a..ec2c1f2ca71b3 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -22,7 +22,7 @@ ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg indexmap = "1.8.0" libloading = { version = "0.6.0", optional = true } once_cell = "1.10.0" -smallvec = "1.6.1" +smallvec = "1.8.1" [patch.crates-io] # Uncomment to use local checkout of cranelift diff --git a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs index cf8fada5320f9..2ecc8b8238b18 100644 --- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs +++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs @@ -6,7 +6,6 @@ // Regression test for issue #91827. #![feature(const_ptr_offset_from)] -#![feature(const_slice_from_raw_parts)] #![feature(extern_types)] use std::ptr::addr_of; diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch index ce1c6c99b40c8..77f437974c2d6 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch @@ -19,7 +19,7 @@ index 092b7cf..158cf71 100644 #[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {} -#[cfg(target_has_atomic_load_store = "128")] --#[unstable(feature = "integer_atomics", issue = "32976")] +-#[unstable(feature = "integer_atomics", issue = "99069")] -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {} #[cfg(target_has_atomic_load_store = "ptr")] @@ -29,7 +29,7 @@ index 092b7cf..158cf71 100644 #[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {} -#[cfg(target_has_atomic_load_store = "128")] --#[unstable(feature = "integer_atomics", issue = "32976")] +-#[unstable(feature = "integer_atomics", issue = "99069")] -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {} #[cfg(target_has_atomic_load_store = "8")] @@ -46,14 +46,14 @@ index d9de37e..8293fce 100644 -atomic_int! { - cfg(target_has_atomic = "128"), - cfg(target_has_atomic_equal_alignment = "128"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), -- unstable(feature = "integer_atomics", issue = "32976"), +- unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), - "i128", - "#![feature(integer_atomics)]\n\n", @@ -66,14 +66,14 @@ index d9de37e..8293fce 100644 -atomic_int! { - cfg(target_has_atomic = "128"), - cfg(target_has_atomic_equal_alignment = "128"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), -- unstable(feature = "integer_atomics", issue = "32976"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), +- unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), -- unstable(feature = "integer_atomics", issue = "32976"), +- unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), - "u128", - "#![feature(integer_atomics)]\n\n", diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index c3b99b64263f2..6d321c7b298a7 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -24,7 +24,7 @@ pub(crate) fn codegen( unwind_context, kind, tcx.lang_items().oom().is_some(), - tcx.sess.opts.debugging_opts.oom, + tcx.sess.opts.unstable_opts.oom, ); true } else { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fbe830b2b1030..54652623d9401 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -503,6 +503,11 @@ fn codegen_stmt<'tcx>( let val = codegen_operand(fx, operand); lval.write_cvalue(fx, val); } + Rvalue::CopyForDeref(place) => { + let cplace = codegen_place(fx, place); + let val = cplace.to_cvalue(fx); + lval.write_cvalue(fx, val) + } Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { let place = codegen_place(fx, place); let ref_ = place.place_ref(fx, lval.layout()); @@ -635,29 +640,6 @@ fn codegen_stmt<'tcx>( let (ptr, _extra) = operand.load_scalar_pair(fx); lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout)) } - } else if let ty::Adt(adt_def, _substs) = from_ty.kind() { - // enum -> discriminant value - assert!(adt_def.is_enum()); - match to_ty.kind() { - ty::Uint(_) | ty::Int(_) => {} - _ => unreachable!("cast adt {} -> {}", from_ty, to_ty), - } - let to_clif_ty = fx.clif_type(to_ty).unwrap(); - - let discriminant = crate::discriminant::codegen_get_discriminant( - fx, - operand, - fx.layout_of(operand.layout().ty.discriminant_ty(fx.tcx)), - ) - .load_scalar(fx); - - let res = crate::cast::clif_intcast( - fx, - discriminant, - to_clif_ty, - to_ty.is_signed(), - ); - lval.write_cvalue(fx, CValue::by_val(res, dest_layout)); } else { let to_clif_ty = fx.clif_type(to_ty).unwrap(); let from = operand.load_scalar(fx); @@ -686,6 +668,7 @@ fn codegen_stmt<'tcx>( substs, ty::ClosureKind::FnOnce, ) + .expect("failed to normalize and resolve closure during codegen") .polymorphize(fx.tcx); let func_ref = fx.get_function_ref(instance); let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref); @@ -842,6 +825,7 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } } + PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty), PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs index e19070774c6e0..b24e49e94c91e 100644 --- a/compiler/rustc_codegen_cranelift/src/cast.rs +++ b/compiler/rustc_codegen_cranelift/src/cast.rs @@ -144,7 +144,7 @@ pub(crate) fn clif_int_or_float_cast( fx.bcx.ins().fcvt_to_uint_sat(to_ty, from) }; - if let Some(false) = fx.tcx.sess.opts.debugging_opts.saturating_float_casts { + if let Some(false) = fx.tcx.sess.opts.unstable_opts.saturating_float_casts { return val; } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ef72e6efb946b..48972321a9f40 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -167,6 +167,7 @@ pub(crate) fn codegen_const_value<'tcx>( } match const_val { + ConstValue::ZeroSized => unreachable!(), // we already handles ZST above ConstValue::Scalar(x) => match x { Scalar::Int(int) => { if fx.clif_type(layout.ty).is_some() { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 476d6a54e1256..bbcb9591373dd 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -140,7 +140,7 @@ impl<'tcx> DebugContext<'tcx> { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site // (unless the crate is being compiled with `-Z debug-macros`). - let span = if !span.from_expansion() || tcx.sess.opts.debugging_opts.debug_macros { + let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros { span } else { // Walk up the macro expansion chain until we reach a non-expanded span. diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 05457ce15e9a7..3cd1ef5639ef9 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -33,7 +33,7 @@ fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectM // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections // can easily double the amount of time necessary to perform linking. - builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); + builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false)); ObjectModule::new(builder) } @@ -66,7 +66,11 @@ fn emit_module( let work_product = if backend_config.disable_incr_cache { None } else { - rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(tcx.sess, &name, &tmp_file) + rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( + tcx.sess, + &name, + &[("o", &tmp_file)], + ) }; ModuleCodegenResult( @@ -82,7 +86,10 @@ fn reuse_workproduct_for_cgu( ) -> CompiledModule { let work_product = cgu.previous_work_product(tcx); let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str())); - let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &work_product.saved_file); + let source_file = rustc_incremental::in_incr_comp_dir_sess( + &tcx.sess, + &work_product.saved_files.get("o").expect("no saved object file in work product"), + ); if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) { tcx.sess.err(&format!( "unable to copy {} to {}: {}", diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 6937e658ed5ee..eafae1cdc8af0 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -676,7 +676,7 @@ fn codegen_regular_intrinsic_call<'tcx>( && !layout.might_permit_raw_init( fx, InitKind::Zero, - fx.tcx.sess.opts.debugging_opts.strict_init_checks) { + fx.tcx.sess.opts.unstable_opts.strict_init_checks) { with_no_trimmed_paths!({ crate::base::codegen_panic( @@ -692,7 +692,7 @@ fn codegen_regular_intrinsic_call<'tcx>( && !layout.might_permit_raw_init( fx, InitKind::Uninit, - fx.tcx.sess.opts.debugging_opts.strict_init_checks) { + fx.tcx.sess.opts.unstable_opts.strict_init_checks) { with_no_trimmed_paths!({ crate::base::codegen_panic( diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 9d2e12f98984a..3ed3453c6c7b3 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -79,7 +79,7 @@ mod prelude { pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, - TypeFoldable, UintTy, + TypeFoldable, TypeVisitable, UintTy, }; pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx}; @@ -167,7 +167,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> { + fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> { vec![] } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index a68225de58b32..8ff35d2f76dbf 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -615,6 +615,14 @@ impl<'tcx> CPlace<'tcx> { } } + pub(crate) fn place_opaque_cast( + self, + fx: &mut FunctionCx<'_, '_, 'tcx>, + ty: Ty<'tcx>, + ) -> CPlace<'tcx> { + CPlace { inner: self.inner, layout: fx.layout_of(ty) } + } + pub(crate) fn place_field( self, fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index c761e5aabd107..58efb81e80011 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -117,7 +117,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam let name = OomStrategy::SYMBOL.to_string(); let global = context.new_global(None, GlobalKind::Exported, i8, name); - let value = tcx.sess.opts.debugging_opts.oom.should_panic(); + let value = tcx.sess.opts.unstable_opts.oom.should_panic(); let value = context.new_rvalue_from_int(i8, value as i32); global.global_set_initializer_rvalue(value); } diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index e4ecbd46f0c42..8f9f6f98faf81 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -96,7 +96,7 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_ // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292). context.add_command_line_option("-fno-strict-aliasing"); - if tcx.sess.opts.debugging_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) { + if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) { context.add_command_line_option("-ffunction-sections"); context.add_command_line_option("-fdata-sections"); } diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 76419b103d049..c1041125ecce7 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -1,6 +1,6 @@ use gccjit::{FunctionType, RValue}; use rustc_codegen_ssa::traits::BaseTypeMethods; -use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::{self, Instance, TypeVisitable}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use crate::abi::FnAbiGccExt; diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ce341406eaf45..fc391f53f18e7 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -9,10 +9,8 @@ use rustc_codegen_ssa::traits::{ StaticMethods, }; use rustc_middle::mir::Mutability; -use rustc_middle::ty::ScalarInt; use rustc_middle::ty::layout::{TyAndLayout, LayoutOf}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; -use rustc_span::Symbol; use rustc_target::abi::{self, HasDataLayout, Pointer, Size}; use crate::consts::const_alloc_to_gcc; @@ -125,12 +123,15 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.context.new_rvalue_from_double(typ, val) } - fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) { - let s_str = s.as_str(); - let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| { - self.global_string(s_str) - }); - let len = s_str.len(); + fn const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>) { + let str_global = *self + .const_str_cache + .borrow_mut() + .raw_entry_mut() + .from_key(s) + .or_insert_with(|| (s.to_owned(), self.global_string(s))) + .1; + let len = s.len(); let cs = self.const_ptrcast(str_global.get_address(None), self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)), ); @@ -157,13 +158,13 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { None } + fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> { + self.const_undef(self.type_ix(0)) + } + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { - Scalar::Int(ScalarInt::ZST) => { - assert_eq!(0, layout.size(self).bytes()); - self.const_undef(self.type_ix(0)) - } Scalar::Int(int) => { let data = int.assert_bits(layout.size(self)); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 44f36cfa4cad4..478f6d893dd0f 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; use rustc_session::Session; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; @@ -101,7 +101,7 @@ pub struct CodegenCx<'gcc, 'tcx> { pub global_lvalues: RefCell<FxHashMap<RValue<'gcc>, LValue<'gcc>>>, /// Cache of constant strings, - pub const_str_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>, + pub const_str_cache: RefCell<FxHashMap<String, LValue<'gcc>>>, /// Cache of globals. pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>, diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 5bfdeb8b93a48..c21e0c5a35b80 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -6,7 +6,14 @@ * TODO(antoyo): remove the patches. */ -#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)] +#![feature( + rustc_private, + decl_macro, + associated_type_bounds, + never_type, + trusted_len, + hash_raw_entry +)] #![allow(broken_intra_doc_links)] #![recursion_limit="256"] #![warn(rust_2018_idioms)] @@ -133,8 +140,8 @@ impl CodegenBackend for GccCodegenBackend { ) } - fn target_features(&self, sess: &Session) -> Vec<Symbol> { - target_features(sess) + fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> { + target_features(sess, allow_unstable) } } @@ -291,12 +298,12 @@ pub fn target_cpu(sess: &Session) -> &str { } } -pub fn target_features(sess: &Session) -> Vec<Symbol> { +pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { supported_target_features(sess) .iter() .filter_map( |&(feature, gate)| { - if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } + if sess.is_nightly_build() || allow_unstable || gate.is_none() { Some(feature) } else { None } }, ) .filter(|_feature| { diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index e21d40b6c37e3..9468a1ef4bbbb 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -1,7 +1,7 @@ use rustc_codegen_ssa::traits::PreDefineMethods; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::{self, Instance, TypeVisitable}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_span::def_id::DefId; diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 569ee2925b13c..524d10fb5e24d 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use gccjit::{Struct, Type}; use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; use rustc_middle::bug; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index b486af133760f..d8fbd0a84fb36 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -31,6 +31,6 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_serialize = { path = "../rustc_serialize" } rustc_target = { path = "../rustc_target" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index cc8b3a1a4e401..d4437bd449d50 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -37,7 +37,7 @@ fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool { // LLVM prior to version 12 had known miscompiles in the presence of // noalias attributes (see #54878), but we don't support earlier // versions at all anymore. We now enable mutable noalias by default. - cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true) + cx.tcx.sess.opts.unstable_opts.mutable_noalias.unwrap_or(true) } const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] = diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index f935acb1a7ea3..72961ae888e5f 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -145,7 +145,7 @@ pub(crate) unsafe fn codegen( if tcx.sess.target.default_hidden_visibility { llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); } - let val = tcx.sess.opts.debugging_opts.oom.should_panic(); + let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::LLVMSetInitializer(ll_g, llval); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 9394d60134f8c..32bfa5094c3eb 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -56,7 +56,7 @@ pub fn sanitize_attrs<'ll>( no_sanitize: SanitizerSet, ) -> SmallVec<[&'ll Attribute; 4]> { let mut attrs = SmallVec::new(); - let enabled = cx.tcx.sess.opts.debugging_opts.sanitizer - no_sanitize; + let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize; if enabled.contains(SanitizerSet::ADDRESS) { attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx)); } @@ -136,7 +136,7 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { if cx .sess() .opts - .debugging_opts + .unstable_opts .sanitizer .intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) { @@ -149,7 +149,7 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { } // probestack doesn't play nice either with gcov profiling. - if cx.sess().opts.debugging_opts.profile { + if cx.sess().opts.unstable_opts.profile { return None; } @@ -275,7 +275,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( to_add.push(uwtable_attr(cx.llcx)); } - if cx.sess().opts.debugging_opts.profile_sample_use.is_some() { + if cx.sess().opts.unstable_opts.profile_sample_use.is_some() { to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile")); } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index da9d8b5fb334a..bccc2a995a30c 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -351,7 +351,7 @@ fn string_to_io_error(s: String) -> io::Error { fn find_binutils_dlltool(sess: &Session) -> OsString { assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc); - if let Some(dlltool_path) = &sess.opts.debugging_opts.dlltool { + if let Some(dlltool_path) = &sess.opts.unstable_opts.dlltool { return dlltool_path.clone().into_os_string(); } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 38402e0431379..be539499b5610 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -325,20 +325,6 @@ fn fat_lto( drop(linker); save_temp_bitcode(cgcx, &module, "lto.input"); - // Fat LTO also suffers from the invalid DWARF issue similar to Thin LTO. - // Here we rewrite all `DICompileUnit` pointers if there is only one `DICompileUnit`. - // This only works around the problem when codegen-units = 1. - // Refer to the comments in the `optimize_thin_module` function for more details. - let mut cu1 = ptr::null_mut(); - let mut cu2 = ptr::null_mut(); - unsafe { llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2) }; - if !cu2.is_null() { - let _timer = - cgcx.prof.generic_activity_with_arg("LLVM_fat_lto_patch_debuginfo", &*module.name); - unsafe { llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1) }; - save_temp_bitcode(cgcx, &module, "fat-lto-after-patch"); - } - // Internalize everything below threshold to help strip out more modules and such. unsafe { let ptr = symbols_below_threshold.as_ptr(); @@ -769,7 +755,7 @@ pub unsafe fn optimize_thin_module( // an error. let mut cu1 = ptr::null_mut(); let mut cu2 = ptr::null_mut(); - llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); + llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); if !cu2.is_null() { let msg = "multiple source DICompileUnits found"; return Err(write::llvm_err(&diag_handler, msg)); @@ -858,7 +844,7 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name()); - llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1); + llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index ab8874d796df2..2b465ce40e7d4 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -107,7 +107,7 @@ pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut ll let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() { tcx.output_filenames(()).split_dwarf_path( tcx.sess.split_debuginfo(), - tcx.sess.opts.debugging_opts.split_dwarf_kind, + tcx.sess.opts.unstable_opts.split_dwarf_kind, Some(mod_name), ) } else { @@ -182,9 +182,9 @@ pub fn target_machine_factory( let use_softfp = sess.opts.cg.soft_float; let ffunction_sections = - sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections); + sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections); let fdata_sections = ffunction_sections; - let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names; + let funique_section_names = !sess.opts.unstable_opts.no_unique_section_names; let code_model = to_llvm_code_model(sess.code_model()); @@ -202,15 +202,15 @@ pub fn target_machine_factory( let features = CString::new(target_features.join(",")).unwrap(); let abi = SmallCStr::new(&sess.target.llvm_abiname); let trap_unreachable = - sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); - let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; + sess.opts.unstable_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); + let emit_stack_size_section = sess.opts.unstable_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); let relax_elf_relocations = - sess.opts.debugging_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations); + sess.opts.unstable_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations); let use_init_array = - !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); + !sess.opts.unstable_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); let path_mapping = sess.source_map().path_mapping().clone(); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index c41a41980eb0b..4a4cccb490d1c 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -28,7 +28,7 @@ use std::ffi::CStr; use std::iter; use std::ops::Deref; use std::ptr; -use tracing::debug; +use tracing::{debug, instrument}; // All Builders must have an llfn associated with them #[must_use] @@ -464,15 +464,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + #[instrument(level = "trace", skip(self))] fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> { - debug!("PlaceRef::load: {:?}", place); - assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); if place.layout.is_zst() { return OperandRef::new_zst(self, place.layout); } + #[instrument(level = "trace", skip(bx))] fn scalar_load_metadata<'a, 'll, 'tcx>( bx: &mut Builder<'a, 'll, 'tcx>, load: &'ll Value, @@ -1064,11 +1064,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { dst: &'ll Value, cmp: &'ll Value, src: &'ll Value, - order: rustc_codegen_ssa::common::AtomicOrdering, + mut order: rustc_codegen_ssa::common::AtomicOrdering, failure_order: rustc_codegen_ssa::common::AtomicOrdering, weak: bool, ) -> &'ll Value { let weak = if weak { llvm::True } else { llvm::False }; + if llvm_util::get_version() < (13, 0, 0) { + use rustc_codegen_ssa::common::AtomicOrdering::*; + // Older llvm has the pre-C++17 restriction on + // success and failure memory ordering, + // requiring the former to be at least as strong as the latter. + // So, for llvm 12, we upgrade the success ordering to a stronger + // one if necessary. + match (order, failure_order) { + (Relaxed, Acquire) => order = Acquire, + (Release, Acquire) => order = AcquireRelease, + (_, SequentiallyConsistent) => order = SequentiallyConsistent, + _ => {} + } + } unsafe { llvm::LLVMRustBuildAtomicCmpXchg( self.llbuilder, diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index ac423a2270320..72155d874a257 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*; use tracing::debug; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::{self, Instance, TypeVisitable}; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b69d7a000ee9a..77cbbf4c6cacf 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -13,8 +13,6 @@ use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::ScalarInt; -use rustc_span::symbol::Symbol; use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size}; use libc::{c_char, c_uint}; @@ -109,8 +107,7 @@ impl<'ll> CodegenCx<'ll, '_> { pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { unsafe { assert_eq!(idx as c_uint as u64, idx); - let us = &[idx as c_uint]; - let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); + let r = llvm::LLVMGetAggregateElement(v, idx as c_uint).unwrap(); debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r); @@ -181,22 +178,27 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMConstReal(t, val) } } - fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) { - let s_str = s.as_str(); - let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| { - let sc = self.const_bytes(s_str.as_bytes()); - let sym = self.generate_local_symbol_name("str"); - let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| { - bug!("symbol `{}` is already defined", sym); - }); - unsafe { - llvm::LLVMSetInitializer(g, sc); - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); - } - g - }); - let len = s_str.len(); + fn const_str(&self, s: &str) -> (&'ll Value, &'ll Value) { + let str_global = *self + .const_str_cache + .borrow_mut() + .raw_entry_mut() + .from_key(s) + .or_insert_with(|| { + let sc = self.const_bytes(s.as_bytes()); + let sym = self.generate_local_symbol_name("str"); + let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + unsafe { + llvm::LLVMSetInitializer(g, sc); + llvm::LLVMSetGlobalConstant(g, True); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); + } + (s.to_owned(), g) + }) + .1; + let len = s.len(); let cs = consts::ptrcast( str_global, self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)), @@ -220,13 +222,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { }) } + fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value { + self.const_undef(self.type_ix(0)) + } + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { - Scalar::Int(ScalarInt::ZST) => { - assert_eq!(0, layout.size(self).bytes()); - self.const_undef(self.type_ix(0)) - } Scalar::Int(int) => { let data = int.assert_bits(layout.size(self)); let llval = self.const_uint_big(self.type_ix(bitsize), data); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5bbbfe9a4ab78..2b16ae1a88de0 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -64,7 +64,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< // See https://github.com/rust-lang/rust/issues/84565. 1 } else { - cx.sess().opts.debugging_opts.uninit_const_chunk_threshold + cx.sess().opts.unstable_opts.uninit_const_chunk_threshold }; let allow_uninit_chunks = chunks.clone().take(max.saturating_add(1)).count() <= max; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index c007728095f79..5857b83f6c971 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -26,7 +26,6 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection}; use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; use rustc_target::abi::{ call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, }; @@ -56,7 +55,7 @@ pub struct CodegenCx<'ll, 'tcx> { pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>, /// Cache of constant strings, - pub const_str_cache: RefCell<FxHashMap<Symbol, &'ll Value>>, + pub const_str_cache: RefCell<FxHashMap<String, &'ll Value>>, /// Reverse-direction for const ptrs cast from globals. /// @@ -276,7 +275,7 @@ pub unsafe fn create_module<'ll>( } } - if let Some(BranchProtection { bti, pac_ret }) = sess.opts.debugging_opts.branch_protection { + if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch != "aarch64" { sess.err("-Zbranch-protection is only supported on aarch64"); } else { @@ -309,7 +308,7 @@ pub unsafe fn create_module<'ll>( } // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). - if let CFProtection::Branch | CFProtection::Full = sess.opts.debugging_opts.cf_protection { + if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Override, @@ -317,7 +316,7 @@ pub unsafe fn create_module<'ll>( 1, ) } - if let CFProtection::Return | CFProtection::Full = sess.opts.debugging_opts.cf_protection { + if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Override, @@ -326,7 +325,7 @@ pub unsafe fn create_module<'ll>( ) } - if sess.opts.debugging_opts.virtual_function_elimination { + if sess.opts.unstable_opts.virtual_function_elimination { llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Error, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index d5f39a4567066..f8bd2d234f32a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -824,7 +824,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( output_filenames .split_dwarf_path( tcx.sess.split_debuginfo(), - tcx.sess.opts.debugging_opts.split_dwarf_kind, + tcx.sess.opts.unstable_opts.split_dwarf_kind, Some(codegen_unit_name), ) // We get a path relative to the working directory from split_dwarf_path @@ -881,15 +881,15 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( split_name.len(), kind, 0, - tcx.sess.opts.debugging_opts.split_dwarf_inlining, + tcx.sess.opts.unstable_opts.split_dwarf_inlining, ); - if tcx.sess.opts.debugging_opts.profile { + if tcx.sess.opts.unstable_opts.profile { let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata); let default_gcda_path = &output_filenames.with_extension("gcda"); let gcda_path = - tcx.sess.opts.debugging_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); + tcx.sess.opts.unstable_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); let gcov_cu_info = [ path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")), @@ -1559,7 +1559,7 @@ pub fn create_vtable_di_node<'ll, 'tcx>( ) { // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in // LLVM at the moment. - if cx.sess().opts.debugging_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat { + if cx.sess().opts.unstable_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat { vcall_visibility_metadata(cx, ty, poly_trait_ref, vtable); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 87fbb737ea8a9..8fc8118849bae 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -93,8 +93,9 @@ impl<'tcx> UniqueTypeId<'tcx> { /// Right now this takes the form of a hex-encoded opaque hash value. pub fn generate_unique_id_string(self, tcx: TyCtxt<'tcx>) -> String { let mut hasher = StableHasher::new(); - let mut hcx = tcx.create_stable_hashing_context(); - hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher)); + tcx.with_stable_hashing_context(|mut hcx| { + hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher)) + }); hasher.finish::<Fingerprint>().to_hex() } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 71699b5cf3830..cf591295b8468 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -27,7 +27,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeVisitable}; use rustc_session::config::{self, DebugInfo}; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -97,23 +97,26 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder); - // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than macOS currently understands. We can - // instruct LLVM to emit an older version of dwarf, however, - // for macOS to understand. For more info see #11352 - // This can be overridden using --llvm-opts -dwarf-version,N. - // Android has the same issue (#22398) - if let Some(version) = sess.target.dwarf_version { + if !sess.target.is_like_msvc { + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + let dwarf_version = sess + .opts + .unstable_opts + .dwarf_version + .unwrap_or(sess.target.default_dwarf_version); llvm::LLVMRustAddModuleFlag( self.llmod, llvm::LLVMModFlagBehavior::Warning, "Dwarf Version\0".as_ptr().cast(), - version, - ) - } - - // Indicate that we want CodeView debug information on MSVC - if sess.target.is_like_msvc { + dwarf_version, + ); + } else { + // Indicate that we want CodeView debug information on MSVC llvm::LLVMRustAddModuleFlag( self.llmod, llvm::LLVMModFlagBehavior::Warning, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 6713a75673550..25ce1cef9440f 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -5,7 +5,8 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(let_chains)] +#![feature(hash_raw_entry)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(extern_types)] #![feature(once_cell)] @@ -323,8 +324,8 @@ impl CodegenBackend for LlvmCodegenBackend { llvm_util::print_version(); } - fn target_features(&self, sess: &Session) -> Vec<Symbol> { - target_features(sess) + fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> { + target_features(sess, allow_unstable) } fn codegen_crate<'tcx>( @@ -354,7 +355,7 @@ impl CodegenBackend for LlvmCodegenBackend { .join(sess); sess.time("llvm_dump_timing_file", || { - if sess.opts.debugging_opts.llvm_time_trace { + if sess.opts.unstable_opts.llvm_time_trace { let file_name = outputs.with_extension("llvm_timings.json"); llvm_util::time_trace_profiler_finish(&file_name); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index b831423994f24..0ad65e5d99bb4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1134,11 +1134,7 @@ extern "C" { pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; - pub fn LLVMConstExtractValue( - AggConstant: &Value, - IdxList: *const c_uint, - NumIdx: c_uint, - ) -> &Value; + pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>; // Operations on global variables, functions, and aliases (globals) pub fn LLVMIsDeclaration(Global: &Value) -> Bool; @@ -1623,7 +1619,7 @@ extern "C" { B: &Builder<'a>, Val: &'a Value, DestTy: &'a Type, - IsSized: bool, + IsSigned: bool, ) -> &'a Value; // Comparisons @@ -2512,8 +2508,12 @@ extern "C" { len: usize, out_len: &mut usize, ) -> *const u8; - pub fn LLVMRustLTOGetDICompileUnit(M: &Module, CU1: &mut *mut c_void, CU2: &mut *mut c_void); - pub fn LLVMRustLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); + pub fn LLVMRustThinLTOGetDICompileUnit( + M: &Module, + CU1: &mut *mut c_void, + CU2: &mut *mut c_void, + ); + pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>; pub fn LLVMRustLinkerAdd( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ce6c6e3215c9b..a0a640473eb51 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -87,7 +87,7 @@ unsafe fn configure_llvm(sess: &Session) { add("-debug-pass=Structure", false); } if sess.target.generate_arange_section - && !sess.opts.debugging_opts.no_generate_arange_section + && !sess.opts.unstable_opts.no_generate_arange_section { add("-generate-arange-section", false); } @@ -102,7 +102,7 @@ unsafe fn configure_llvm(sess: &Session) { add("-enable-machine-outliner=never", false); } - match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) { + match sess.opts.unstable_opts.merge_functions.unwrap_or(sess.target.merge_functions) { MergeFunctions::Disabled | MergeFunctions::Trampolines => {} MergeFunctions::Aliases => { add("-mergefunc-use-aliases", false); @@ -125,7 +125,7 @@ unsafe fn configure_llvm(sess: &Session) { } } - if sess.opts.debugging_opts.llvm_time_trace { + if sess.opts.unstable_opts.llvm_time_trace { llvm::LLVMTimeTraceProfilerInitialize(); } @@ -133,11 +133,11 @@ unsafe fn configure_llvm(sess: &Session) { // Use the legacy plugin registration if we don't use the new pass manager if !should_use_new_llvm_pass_manager( - &sess.opts.debugging_opts.new_llvm_pass_manager, + &sess.opts.unstable_opts.new_llvm_pass_manager, &sess.target.arch, ) { // Register LLVM plugins by loading them into the compiler process. - for plugin in &sess.opts.debugging_opts.llvm_plugins { + for plugin in &sess.opts.unstable_opts.llvm_plugins { let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e)); debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin); @@ -233,26 +233,29 @@ pub fn check_tied_features( // Used to generate cfg variables and apply features // Must express features in the way Rust understands them -pub fn target_features(sess: &Session) -> Vec<Symbol> { +pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { let target_machine = create_informational_target_machine(sess); - let mut features: Vec<Symbol> = - supported_target_features(sess) - .iter() - .filter_map(|&(feature, gate)| { - if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } - }) - .filter(|feature| { - // check that all features in a given smallvec are enabled - for llvm_feature in to_llvm_features(sess, feature) { - let cstr = SmallCStr::new(llvm_feature); - if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { - return false; - } + let mut features: Vec<Symbol> = supported_target_features(sess) + .iter() + .filter_map(|&(feature, gate)| { + if sess.is_nightly_build() || allow_unstable || gate.is_none() { + Some(feature) + } else { + None + } + }) + .filter(|feature| { + // check that all features in a given smallvec are enabled + for llvm_feature in to_llvm_features(sess, feature) { + let cstr = SmallCStr::new(llvm_feature); + if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { + return false; } - true - }) - .map(|feature| Symbol::intern(feature)) - .collect(); + } + true + }) + .map(|feature| Symbol::intern(feature)) + .collect(); // LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64 // (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use @@ -538,7 +541,7 @@ fn backend_feature_name(s: &str) -> Option<&str> { } pub fn tune_cpu(sess: &Session) -> Option<&str> { - let name = sess.opts.debugging_opts.tune_cpu.as_ref()?; + let name = sess.opts.unstable_opts.tune_cpu.as_ref()?; Some(handle_native(name)) } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index a3053742aad99..6e94284852f35 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; -use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::{self, Instance, TypeVisitable}; use rustc_session::config::CrateType; use rustc_target::spec::RelocModel; use tracing::debug; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 862805236311d..9f0e6c80b19a7 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 1bdc473c29b6e..faabea92f5a6c 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -18,7 +18,7 @@ thorin-dwp = "0.2" pathdiff = "0.2.0" serde_json = "1.0.59" snap = "1" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } regex = "1.4" rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 553486ae8ec65..1cb8d34238129 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,13 +1,12 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_session::cstore::DllImport; use rustc_session::Session; -use rustc_span::symbol::Symbol; use std::io; use std::path::{Path, PathBuf}; pub(super) fn find_library( - name: Symbol, + name: &str, verbatim: bool, search_paths: &[PathBuf], sess: &Session, diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 6c29692bd3bfe..9b0ba34135c11 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -7,7 +7,6 @@ use std::io; use std::mem; use std::process::{self, Output}; -use rustc_span::symbol::Symbol; use rustc_target::spec::LldFlavor; #[derive(Clone)] @@ -47,11 +46,6 @@ impl Command { self } - pub fn sym_arg(&mut self, arg: Symbol) -> &mut Command { - self.arg(arg.as_str()); - self - } - pub fn args<I>(&mut self, args: I) -> &mut Command where I: IntoIterator<Item: AsRef<OsStr>>, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 72aa790c36357..878a670cba3ef 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -6,6 +6,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; +use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; @@ -28,10 +29,7 @@ use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{create_rmeta_file, MetadataPosition}; use super::rpath::{self, RPathConfig}; -use crate::{ - looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, - METADATA_FILENAME, -}; +use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib}; use cc::windows_registry; use regex::Regex; @@ -67,7 +65,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); for &crate_type in sess.crate_types().iter() { // Ignore executable crates if we have -Z no-codegen, as they will error. - if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) + if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen()) && !output_metadata && crate_type == CrateType::Executable { @@ -151,11 +149,23 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( return; } - let remove_temps_from_module = |module: &CompiledModule| { - if let Some(ref obj) = module.object { - ensure_removed(sess.diagnostic(), obj); - } - }; + let maybe_remove_temps_from_module = + |preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| { + if !preserve_objects { + if let Some(ref obj) = module.object { + ensure_removed(sess.diagnostic(), obj); + } + } + + if !preserve_dwarf_objects { + if let Some(ref dwo_obj) = module.dwarf_object { + ensure_removed(sess.diagnostic(), dwo_obj); + } + } + }; + + let remove_temps_from_module = + |module: &CompiledModule| maybe_remove_temps_from_module(false, false, module); // Otherwise, always remove the metadata and allocator module temporaries. if let Some(ref metadata_module) = codegen_results.metadata_module { @@ -177,15 +187,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( debug!(?preserve_objects, ?preserve_dwarf_objects); for module in &codegen_results.modules { - if !preserve_objects { - remove_temps_from_module(module); - } - - if !preserve_dwarf_objects { - if let Some(ref obj) = module.dwarf_object { - ensure_removed(sess.diagnostic(), obj); - } - } + maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module); } }); @@ -237,22 +239,6 @@ pub fn each_linked_rlib( Ok(()) } -/// We use a temp directory here to avoid races between concurrent rustc processes, -/// such as builds in the same directory using the same filename for metadata while -/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a -/// directory being searched for `extern crate` (observing an incomplete file). -/// The returned path is the temporary file containing the complete metadata. -pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf { - let out_filename = tmpdir.as_ref().join(METADATA_FILENAME); - let result = fs::write(&out_filename, metadata); - - if let Err(e) = result { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); - } - - out_filename -} - /// Create an 'rlib'. /// /// An rlib in its current incarnation is essentially a renamed .a file. The rlib primarily contains @@ -354,7 +340,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } if let Some(name) = lib.name { let location = - find_library(name, lib.verbatim.unwrap_or(false), &lib_search_paths, sess); + find_library(name.as_str(), lib.verbatim.unwrap_or(false), &lib_search_paths, sess); ab.add_archive(&location, |_| false).unwrap_or_else(|e| { sess.fatal(&format!( "failed to add native library {}: {}", @@ -591,7 +577,7 @@ fn link_dwarf_object<'a>( let mut package = thorin::DwarfPackage::new(&thorin_sess); // Input objs contain .o/.dwo files from the current crate. - match sess.opts.debugging_opts.split_dwarf_kind { + match sess.opts.unstable_opts.split_dwarf_kind { SplitDwarfKind::Single => { for input_obj in cg_results.modules.iter().filter_map(|m| m.object.as_ref()) { package.add_input_object(input_obj)?; @@ -649,6 +635,7 @@ fn link_dwarf_object<'a>( sess.struct_err("linking dwarf objects with thorin failed") .note(&format!("{:?}", e)) .emit(); + sess.abort_if_errors(); } } } @@ -1017,7 +1004,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // Temporarily support both -Z strip and -C strip fn strip_value(sess: &Session) -> Strip { - match (sess.opts.debugging_opts.strip, sess.opts.cg.strip) { + match (sess.opts.unstable_opts.strip, sess.opts.cg.strip) { (s, Strip::None) => s, (_, s) => s, } @@ -1069,7 +1056,7 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d return; } - let sanitizer = sess.opts.debugging_opts.sanitizer; + let sanitizer = sess.opts.unstable_opts.sanitizer; if sanitizer.contains(SanitizerSet::ADDRESS) { link_sanitizer_runtime(sess, linker, "asan"); } @@ -1117,7 +1104,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { let path = find_sanitizer_runtime(&sess, &filename); let rpath = path.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); - linker.link_dylib(Symbol::intern(&filename), false, true); + linker.link_dylib(&filename, false, true); } else { let filename = format!("librustc{}_rt.{}.a", channel, name); let path = find_sanitizer_runtime(&sess, &filename).join(&filename); @@ -1248,7 +1235,7 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) { return (false, false); } - match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) { + match (sess.split_debuginfo(), sess.opts.unstable_opts.split_dwarf_kind) { // If there is no split debuginfo then do not preserve objects. (SplitDebuginfo::Off, _) => (false, false), // If there is packed split debuginfo, then the debuginfo in the objects @@ -1596,7 +1583,7 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) if let Some(args) = sess.target.pre_link_args.get(&flavor) { cmd.args(args.iter().map(Deref::deref)); } - cmd.args(&sess.opts.debugging_opts.pre_link_args); + cmd.args(&sess.opts.unstable_opts.pre_link_args); } /// Add a link script embedded in the target, if applicable. @@ -1804,7 +1791,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: /// Add options making relocation sections in the produced ELF files read-only /// and suppressing lazy binding. fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) { - match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.relro_level) { + match sess.opts.unstable_opts.relro_level.unwrap_or(sess.target.relro_level) { RelroLevel::Full => cmd.full_relro(), RelroLevel::Partial => cmd.partial_relro(), RelroLevel::Off => cmd.no_relro(), @@ -1952,7 +1939,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // (or alternatively link all native libraries after their respective crates). // This change is somewhat breaking in practice due to local static libraries being linked // as whole-archive (#85144), so removing whole-archive may be a pre-requisite. - if sess.opts.debugging_opts.link_native_libraries { + if sess.opts.unstable_opts.link_native_libraries { add_local_native_libraries(cmd, sess, codegen_results); } @@ -1964,7 +1951,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // If -Zlink-native-libraries=false is set, then the assumption is that an // external build system already has the native dependencies defined, and it // will provide them to the linker itself. - if sess.opts.debugging_opts.link_native_libraries { + if sess.opts.unstable_opts.link_native_libraries { add_upstream_native_libraries(cmd, sess, codegen_results); } @@ -2032,7 +2019,7 @@ fn add_order_independent_options( add_link_script(cmd, sess, tmpdir, crate_type); if sess.target.os == "fuchsia" && crate_type == CrateType::Executable { - let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) { + let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) { "asan/" } else { "" @@ -2199,6 +2186,7 @@ fn add_local_native_libraries( let Some(name) = lib.name else { continue; }; + let name = name.as_str(); // Skip if this library is the same as the last. last = if (lib.name, lib.kind, lib.verbatim) == last { @@ -2356,12 +2344,13 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // If -Zlink-native-libraries=false is set, then the assumption is that an // external build system already has the native dependencies defined, and it // will provide them to the linker itself. - if sess.opts.debugging_opts.link_native_libraries { + if sess.opts.unstable_opts.link_native_libraries { let mut last = (None, NativeLibKind::Unspecified, None); for lib in &codegen_results.crate_info.native_libraries[&cnum] { let Some(name) = lib.name else { continue; }; + let name = name.as_str(); if !relevant_lib(sess, lib) { continue; } @@ -2519,7 +2508,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } let filestem = cratepath.file_stem().unwrap().to_str().unwrap(); cmd.link_rust_dylib( - Symbol::intern(&unlib(&sess.target, filestem)), + &unlib(&sess.target, filestem), parent.unwrap_or_else(|| Path::new("")), ); } @@ -2551,6 +2540,7 @@ fn add_upstream_native_libraries( let Some(name) = lib.name else { continue; }; + let name = name.as_str(); if !relevant_lib(sess, &lib) { continue; } @@ -2701,7 +2691,7 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> { } fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - if let Some(ld_impl) = sess.opts.debugging_opts.gcc_ld { + if let Some(ld_impl) = sess.opts.unstable_opts.gcc_ld { if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index b5b63942e2c6e..d4a9db4af23a2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -16,7 +16,6 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; use rustc_session::Session; -use rustc_span::symbol::Symbol; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; use cc::windows_registry; @@ -163,13 +162,13 @@ pub fn get_linker<'a>( pub trait Linker { fn cmd(&mut self) -> &mut Command; fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool); - fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); - fn link_framework(&mut self, framework: Symbol, as_needed: bool); - fn link_staticlib(&mut self, lib: Symbol, verbatim: bool); + fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool); + fn link_rust_dylib(&mut self, lib: &str, path: &Path); + fn link_framework(&mut self, framework: &str, as_needed: bool); + fn link_staticlib(&mut self, lib: &str, verbatim: bool); fn link_rlib(&mut self, lib: &Path); fn link_whole_rlib(&mut self, lib: &Path); - fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]); + fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); @@ -304,7 +303,7 @@ impl<'a> GccLinker<'a> { config::OptLevel::Aggressive => "O3", }; - if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use { + if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; self.linker_args(&[ @@ -326,7 +325,7 @@ impl<'a> GccLinker<'a> { // purely to support rustbuild right now, we should get a more // principled solution at some point to force the compiler to pass // the right `-Wl,-install_name` with an `@rpath` in it. - if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { + if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { let mut rpath = OsString::from("@rpath/"); rpath.push(out_filename.file_name().unwrap()); self.linker_args(&[OsString::from("-install_name"), rpath]); @@ -423,8 +422,8 @@ impl<'a> Linker for GccLinker<'a> { } } - fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) { - if self.sess.target.os == "illumos" && lib.as_str() == "c" { + fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) { + if self.sess.target.os == "illumos" && lib == "c" { // libc will be added via late_link_args on illumos so that it will // appear last in the library search order. // FIXME: This should be replaced by a more complete and generic @@ -454,7 +453,7 @@ impl<'a> Linker for GccLinker<'a> { } } } - fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) { + fn link_staticlib(&mut self, lib: &str, verbatim: bool) { self.hint_static(); self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); } @@ -484,20 +483,20 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("-znorelro"); } - fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); } - fn link_framework(&mut self, framework: Symbol, as_needed: bool) { + fn link_framework(&mut self, framework: &str, as_needed: bool) { self.hint_dynamic(); if !as_needed { // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework // flag but we have no way to detect that here. - // self.cmd.arg("-needed_framework").sym_arg(framework); + // self.cmd.arg("-needed_framework").arg(framework); self.sess.warn("`as-needed` modifier not implemented yet for ld64"); } - self.cmd.arg("-framework").sym_arg(framework); + self.cmd.arg("-framework").arg(framework); } // Here we explicitly ask that the entire archive is included into the @@ -506,7 +505,7 @@ impl<'a> Linker for GccLinker<'a> { // don't otherwise explicitly reference them. This can occur for // libraries which are just providing bindings, libraries with generic // functions, etc. - fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { self.hint_static(); let target = &self.sess.target; if !target.is_like_osx { @@ -836,11 +835,11 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/OPT:NOREF,NOICF"); } - fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) { + fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); } - fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) { + fn link_rust_dylib(&mut self, lib: &str, path: &Path) { // When producing a dll, the MSVC linker may not actually emit a // `foo.lib` file if the dll doesn't actually export any symbols, so we // check to see if the file is there and just omit linking to it if it's @@ -851,7 +850,7 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) { + fn link_staticlib(&mut self, lib: &str, verbatim: bool) { self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); } @@ -890,11 +889,11 @@ impl<'a> Linker for MsvcLinker<'a> { fn framework_path(&mut self, _path: &Path) { bug!("frameworks are not supported on windows") } - fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { bug!("frameworks are not supported on windows") } - fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); } fn link_whole_rlib(&mut self, path: &Path) { @@ -1047,8 +1046,8 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg("-L").arg(path); } - fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { - self.cmd.arg("-l").sym_arg(lib); + fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + self.cmd.arg("-l").arg(lib); } fn output_filename(&mut self, path: &Path) { @@ -1059,12 +1058,12 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg(path); } - fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) { + fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { // Emscripten always links statically self.link_staticlib(lib, verbatim); } - fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { // not supported? self.link_staticlib(lib, verbatim); } @@ -1074,7 +1073,7 @@ impl<'a> Linker for EmLinker<'a> { self.link_rlib(lib); } - fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { self.link_dylib(lib, false, true); } @@ -1098,7 +1097,7 @@ impl<'a> Linker for EmLinker<'a> { bug!("frameworks are not supported on Emscripten") } - fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { bug!("frameworks are not supported on Emscripten") } @@ -1237,12 +1236,12 @@ impl<'a> Linker for WasmLd<'a> { } } - fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").sym_arg(lib); + fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { + self.cmd.arg("-l").arg(lib); } - fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { - self.cmd.arg("-l").sym_arg(lib); + fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + self.cmd.arg("-l").arg(lib); } fn link_rlib(&mut self, lib: &Path) { @@ -1271,16 +1270,16 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} - fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { - self.cmd.arg("-l").sym_arg(lib); + fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.cmd.arg("-l").arg(lib); } - fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { panic!("frameworks not supported") } - fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { - self.cmd.arg("-l").sym_arg(lib); + fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { + self.cmd.arg("-l").arg(lib); } fn link_whole_rlib(&mut self, lib: &Path) { @@ -1360,10 +1359,10 @@ pub struct L4Bender<'a> { } impl<'a> Linker for L4Bender<'a> { - fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { + fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { bug!("dylibs are not supported on L4Re"); } - fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { + fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { self.hint_static(); self.cmd.arg(format!("-PC{}", lib)); } @@ -1404,15 +1403,15 @@ impl<'a> Linker for L4Bender<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_rust_dylib(&mut self, _: Symbol, _: &Path) { + fn link_rust_dylib(&mut self, _: &str, _: &Path) { panic!("Rust dylibs not supported"); } - fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { bug!("frameworks not supported on L4Re"); } - fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { self.hint_static(); self.cmd.arg("--whole-archive").arg(format!("-l{}", lib)); self.cmd.arg("--no-whole-archive"); @@ -1617,19 +1616,19 @@ impl<'a> Linker for PtxLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { + fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { panic!("external dylibs not supported") } - fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { + fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { panic!("external dylibs not supported") } - fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) { + fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { panic!("staticlibs not supported") } - fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { panic!("staticlibs not supported") } @@ -1637,7 +1636,7 @@ impl<'a> Linker for PtxLinker<'a> { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { panic!("frameworks not supported") } @@ -1717,19 +1716,19 @@ impl<'a> Linker for BpfLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { + fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { panic!("external dylibs not supported") } - fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { + fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { panic!("external dylibs not supported") } - fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) { + fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { panic!("staticlibs not supported") } - fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { panic!("staticlibs not supported") } @@ -1737,7 +1736,7 @@ impl<'a> Linker for BpfLinker<'a> { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { panic!("frameworks not supported") } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 3dd607adee501..0302c28815ab8 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -16,14 +16,13 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; +use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_target::abi::Endian; use rustc_target::spec::{RelocModel, Target}; -use crate::METADATA_FILENAME; - /// The default metadata loader. This is used by cg_llvm and cg_clif. /// /// # Metadata location diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index f651814be7ea6..d1a267f7643f5 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -232,15 +232,15 @@ fn exported_symbols_provider_local<'tcx>( })); } - if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) { + if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { let mut msan_weak_symbols = Vec::new(); // Similar to profiling, preserve weak msan symbol during LTO. - if tcx.sess.opts.debugging_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) { + if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) { msan_weak_symbols.push("__msan_keep_going"); } - if tcx.sess.opts.debugging_opts.sanitizer_memory_track_origins != 0 { + if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 { msan_weak_symbols.push("__msan_track_origins"); } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 632f07c5c2d80..c2ac21eec6723 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -179,24 +179,24 @@ impl ModuleConfig { SwitchWithOptPath::Disabled ), pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None), - pgo_sample_use: if_regular!(sess.opts.debugging_opts.profile_sample_use.clone(), None), - debug_info_for_profiling: sess.opts.debugging_opts.debug_info_for_profiling, + pgo_sample_use: if_regular!(sess.opts.unstable_opts.profile_sample_use.clone(), None), + debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling, instrument_coverage: if_regular!(sess.instrument_coverage(), false), instrument_gcov: if_regular!( // compiler_builtins overrides the codegen-units settings, // which is incompatible with -Zprofile which requires that // only a single codegen unit is used per crate. - sess.opts.debugging_opts.profile && !is_compiler_builtins, + sess.opts.unstable_opts.profile && !is_compiler_builtins, false ), - sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer, SanitizerSet::empty()), + sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()), sanitizer_recover: if_regular!( - sess.opts.debugging_opts.sanitizer_recover, + sess.opts.unstable_opts.sanitizer_recover, SanitizerSet::empty() ), sanitizer_memory_track_origins: if_regular!( - sess.opts.debugging_opts.sanitizer_memory_track_origins, + sess.opts.unstable_opts.sanitizer_memory_track_origins, 0 ), @@ -247,7 +247,7 @@ impl ModuleConfig { // O2 and O3) since it can be useful for reducing code size. merge_functions: match sess .opts - .debugging_opts + .unstable_opts .merge_functions .unwrap_or(sess.target.merge_functions) { @@ -259,9 +259,9 @@ impl ModuleConfig { }, inline_threshold: sess.opts.cg.inline_threshold, - new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager, + new_llvm_pass_manager: sess.opts.unstable_opts.new_llvm_pass_manager, emit_lifetime_markers: sess.emit_lifetime_markers(), - llvm_plugins: if_regular!(sess.opts.debugging_opts.llvm_plugins.clone(), vec![]), + llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]), } } @@ -494,12 +494,18 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir"); for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) { - if let Some(path) = &module.object { - if let Some((id, product)) = - copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path) - { - work_products.insert(id, product); - } + let mut files = Vec::new(); + if let Some(object_file_path) = &module.object { + files.push(("o", object_file_path.as_path())); + } + if let Some(dwarf_object_file_path) = &module.dwarf_object { + files.push(("dwo", dwarf_object_file_path.as_path())); + } + + if let Some((id, product)) = + copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice()) + { + work_products.insert(id, product); } } @@ -856,29 +862,50 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( assert!(module_config.emit_obj != EmitObj::None); let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); - let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)); - let source_file = in_incr_comp_dir(&incr_comp_session_dir, &module.source.saved_file); - debug!( - "copying pre-existing module `{}` from {:?} to {}", - module.name, - source_file, - obj_out.display() + + let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { + let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path); + debug!( + "copying pre-existing module `{}` from {:?} to {}", + module.name, + source_file, + output_path.display() + ); + match link_or_copy(&source_file, &output_path) { + Ok(_) => Some(output_path), + Err(err) => { + let diag_handler = cgcx.create_diag_handler(); + diag_handler.err(&format!( + "unable to copy {} to {}: {}", + source_file.display(), + output_path.display(), + err + )); + None + } + } + }; + + let object = load_from_incr_comp_dir( + cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)), + &module.source.saved_files.get("o").expect("no saved object file in work product"), ); - if let Err(err) = link_or_copy(&source_file, &obj_out) { - let diag_handler = cgcx.create_diag_handler(); - diag_handler.err(&format!( - "unable to copy {} to {}: {}", - source_file.display(), - obj_out.display(), - err - )); - } + let dwarf_object = + module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| { + let dwarf_obj_out = cgcx + .output_filenames + .split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, Some(&module.name)) + .expect( + "saved dwarf object in work product but `split_dwarf_path` returned `None`", + ); + load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file) + }); WorkItemResult::Compiled(CompiledModule { name: module.name, kind: ModuleKind::Regular, - object: Some(obj_out), - dwarf_object: None, + object, + dwarf_object, bytecode: None, }) } @@ -899,7 +926,7 @@ fn finish_intra_module_work<B: ExtraBackendMethods>( ) -> Result<WorkItemResult<B>, FatalError> { let diag_handler = cgcx.create_diag_handler(); - if !cgcx.opts.debugging_opts.combine_cgu + if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Metadata || module.kind == ModuleKind::Allocator { @@ -1021,14 +1048,13 @@ fn start_executing_work<B: ExtraBackendMethods>( each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); })); - let ol = if tcx.sess.opts.debugging_opts.no_codegen - || !tcx.sess.opts.output_types.should_codegen() - { - // If we know that we won’t be doing codegen, create target machines without optimisation. - config::OptLevel::No - } else { - tcx.backend_optimization_level(()) - }; + let ol = + if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { + // If we know that we won’t be doing codegen, create target machines without optimisation. + config::OptLevel::No + } else { + tcx.backend_optimization_level(()) + }; let backend_features = tcx.global_backend_features(()); let cgcx = CodegenContext::<B> { backend: backend.clone(), @@ -1037,7 +1063,7 @@ fn start_executing_work<B: ExtraBackendMethods>( lto: sess.lto(), fewer_names: sess.fewer_names(), save_temps: sess.opts.cg.save_temps, - time_trace: sess.opts.debugging_opts.llvm_time_trace, + time_trace: sess.opts.unstable_opts.llvm_time_trace, opts: Arc::new(sess.opts.clone()), prof: sess.prof.clone(), exported_symbols, @@ -1060,7 +1086,7 @@ fn start_executing_work<B: ExtraBackendMethods>( target_arch: tcx.sess.target.arch.to_string(), debuginfo: tcx.sess.opts.debuginfo, split_debuginfo: tcx.sess.split_debuginfo(), - split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind, + split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, }; // This is the "main loop" of parallel work happening for parallel codegen. @@ -1319,7 +1345,7 @@ fn start_executing_work<B: ExtraBackendMethods>( .binary_search_by_key(&cost, |&(_, cost)| cost) .unwrap_or_else(|e| e); work_items.insert(insertion_index, (work, cost)); - if !cgcx.opts.debugging_opts.no_parallel_llvm { + if !cgcx.opts.unstable_opts.no_parallel_llvm { helper.request_token(); } } @@ -1439,7 +1465,7 @@ fn start_executing_work<B: ExtraBackendMethods>( }; work_items.insert(insertion_index, (llvm_work_item, cost)); - if !cgcx.opts.debugging_opts.no_parallel_llvm { + if !cgcx.opts.unstable_opts.no_parallel_llvm { helper.request_token(); } assert!(!codegen_aborted); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 7e2e85ead5469..7def30af2b309 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -521,7 +521,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( need_metadata_module: bool, ) -> OngoingCodegen<B> { // Skip crate items and just output metadata in -Z no-codegen mode. - if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { + if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None, 1); ongoing_codegen.codegen_finished(tcx); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 8755d91818d22..8cd5a0fc24759 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -701,16 +701,20 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S // If we cannot evaluate the constant to a known type, we fall back // to emitting a stable hash value of the constant. This isn't very pretty // but we get a deterministic, virtually unique value for the constant. - let hcx = &mut tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - let ct = ct.eval(tcx, ty::ParamEnv::reveal_all()); - hcx.while_hashing_spans(false, |hcx| ct.to_valtree().hash_stable(hcx, &mut hasher)); + // // Let's only emit 64 bits of the hash value. That should be plenty for // avoiding collisions and will make the emitted type names shorter. - // Note: Don't use `StableHashResult` impl of `u64` here directly, since that - // would lead to endianness problems. - let hash: u128 = hasher.finish(); - let hash_short = (hash.to_le() as u64).to_le(); + let hash_short = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + let ct = ct.eval(tcx, ty::ParamEnv::reveal_all()); + hcx.while_hashing_spans(false, |hcx| { + ct.to_valtree().hash_stable(hcx, &mut hasher) + }); + // Note: Don't use `StableHashResult` impl of `u64` here directly, since that + // would lead to endianness problems. + let hash: u128 = hasher.finish(); + (hash.to_le() as u64).to_le() + }); if cpp_like_debuginfo(tcx) { write!(output, "CONST${:x}", hash_short) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 6c30923bc3d73..1802eedf193aa 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -6,6 +6,7 @@ #![feature(associated_type_bounds)] #![feature(strict_provenance)] #![feature(int_roundings)] +#![feature(if_let_guard)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] @@ -63,9 +64,6 @@ pub struct ModuleCodegen<M> { pub kind: ModuleKind, } -// FIXME(eddyb) maybe include the crate name in this? -pub const METADATA_FILENAME: &str = "lib.rmeta"; - impl<M> ModuleCodegen<M> { pub fn into_compiled_module( self, diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 5203ebfad75de..df42d80456690 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> VirtualIndex { let llty = bx.fn_ptr_backend_type(fn_abi); let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty)); - if bx.cx().sess().opts.debugging_opts.virtual_function_elimination + if bx.cx().sess().opts.unstable_opts.virtual_function_elimination && bx.cx().sess().lto() == Lto::Fat { let typeid = diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 80dab115fac46..24da48ead63a2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -15,7 +15,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, ) -> BitSet<mir::Local> { let mir = fx.mir; - let dominators = mir.dominators(); + let dominators = mir.basic_blocks.dominators(); let locals = mir .local_decls .iter() @@ -143,13 +143,13 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, // now that we have moved to the "slice of projections" representation. if let mir::ProjectionElem::Index(local) = elem { self.visit_local( - &local, + local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); } } else { - self.visit_local(&place_ref.local, context, location); + self.visit_local(place_ref.local, context, location); } } } @@ -185,7 +185,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> self.process_place(&place.as_ref(), context, location); } - fn visit_local(&mut self, &local: &mir::Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) { match context { PlaceContext::MutatingUse(MutatingUseContext::Call) | PlaceContext::MutatingUse(MutatingUseContext::Yield) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index db348f2bdd507..745da821c9d76 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::mir::{self, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; use rustc_symbol_mangling::typeid_for_fnabi; @@ -132,6 +132,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, cleanup: Option<mir::BasicBlock>, + copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>], ) { // If there is a cleanup block and the function we're calling can unwind, then // do an invoke, otherwise do a call. @@ -172,6 +173,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some((ret_dest, target)) = destination { bx.switch_to_block(fx.llbb(target)); fx.set_debug_loc(bx, self.terminator.source_info); + for tmp in copied_constant_arguments { + bx.lifetime_end(tmp.llval, tmp.layout.size); + } fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret); } } else { @@ -186,6 +190,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } if let Some((ret_dest, target)) = destination { + for tmp in copied_constant_arguments { + bx.lifetime_end(tmp.llval, tmp.layout.size); + } fx.store_return(bx, ret_dest, &fn_abi.ret, llret); self.funclet_br(fx, bx, target); } else { @@ -415,6 +422,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args, Some((ReturnDest::Nothing, target)), unwind, + &[], ); } @@ -481,8 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (LangItem::PanicBoundsCheck, vec![index, len, location]) } _ => { - let msg_str = Symbol::intern(msg.description()); - let msg = bx.const_str(msg_str); + let msg = bx.const_str(msg.description()); // It's `pub fn panic(expr: &str)`, with the wide reference being passed // as two arguments, and `#[track_caller]` adds an implicit third argument. (LangItem::Panic, vec![msg.0, msg.1, location]) @@ -492,7 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (fn_abi, llfn) = common::build_langcall(&bx, Some(span), lang_item); // Codegen the actual panic invoke/call. - helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup); + helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup, &[]); } fn codegen_abort_terminator( @@ -508,7 +515,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (fn_abi, llfn) = common::build_langcall(&bx, Some(span), LangItem::PanicNoUnwind); // Codegen the actual panic invoke/call. - helper.do_call(self, &mut bx, fn_abi, llfn, &[], None, None); + helper.do_call(self, &mut bx, fn_abi, llfn, &[], None, None, &[]); } /// Returns `true` if this is indeed a panic intrinsic and codegen is done. @@ -563,7 +570,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }) }); - let msg = bx.const_str(Symbol::intern(&msg_str)); + let msg = bx.const_str(&msg_str); let location = self.get_caller_location(bx, source_info).immediate(); // Obtain the panic entry point. @@ -579,6 +586,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &[msg.0, msg.1, location], target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), cleanup, + &[], ); } else { // a NOP @@ -679,7 +687,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { source_info, target, cleanup, - self.cx.tcx().sess.opts.debugging_opts.strict_init_checks, + self.cx.tcx().sess.opts.unstable_opts.strict_init_checks, ) { return; } @@ -786,6 +794,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (args, None) }; + let mut copied_constant_arguments = vec![]; 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(&mut bx, arg); @@ -851,8 +860,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (&mir::Operand::Copy(_), Ref(_, None, _)) | (&mir::Operand::Constant(_), Ref(_, None, _)) => { let tmp = PlaceRef::alloca(&mut bx, op.layout); + bx.lifetime_start(tmp.llval, tmp.layout.size); op.val.store(&mut bx, tmp); op.val = Ref(tmp.llval, None, tmp.align); + copied_constant_arguments.push(tmp); } _ => {} } @@ -925,6 +936,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &llargs, target.as_ref().map(|&target| (ret_dest, target)), cleanup, + &copied_constant_arguments, ); bx.switch_to_block(bb_fail); @@ -942,6 +954,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &llargs, target.as_ref().map(|&target| (ret_dest, target)), cleanup, + &copied_constant_arguments, ); } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index f2d1827c792db..8c3186efc6302 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return span; } - if span.from_expansion() && !self.cx.sess().opts.debugging_opts.debug_macros { + if span.from_expansion() && !self.cx.sess().opts.unstable_opts.debug_macros { // Walk up the macro expansion chain until we reach a non-expanded span. // We also stop at the function body level because no line stepping can occur // at the level above that. diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 0ed4c3f1d9430..645afae30d887 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -376,32 +376,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst - name if name_str.starts_with("atomic_") => { + // "atomic_<operation>[_<ordering>]" + name if let Some(atomic) = name_str.strip_prefix("atomic_") => { use crate::common::AtomicOrdering::*; use crate::common::{AtomicRmwBinOp, SynchronizationScope}; - let split: Vec<_> = name_str.split('_').collect(); - - let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; - let (order, failorder) = match split.len() { - 2 => (SequentiallyConsistent, SequentiallyConsistent), - 3 => match split[2] { - "unordered" => (Unordered, Unordered), - "relaxed" => (Relaxed, Relaxed), - "acq" => (Acquire, Acquire), - "rel" => (Release, Relaxed), - "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Relaxed), - "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), - _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), - }, - 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Relaxed), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Relaxed), - _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), - }, - _ => bx.sess().fatal("Atomic intrinsic not in correct format"), + let Some((instruction, ordering)) = atomic.split_once('_') else { + bx.sess().fatal("Atomic intrinsic missing memory ordering"); + }; + + let parse_ordering = |bx: &Bx, s| match s { + "unordered" => Unordered, + "relaxed" => Relaxed, + "acquire" => Acquire, + "release" => Release, + "acqrel" => AcquireRelease, + "seqcst" => SequentiallyConsistent, + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), }; let invalid_monomorphization = |ty| { @@ -416,11 +407,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); }; - match split[1] { + match instruction { "cxchg" | "cxchgweak" => { + let Some((success, failure)) = ordering.split_once('_') else { + bx.sess().fatal("Atomic compare-exchange intrinsic missing failure memory ordering"); + }; let ty = substs.type_at(0); if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { - let weak = split[1] == "cxchgweak"; + let weak = instruction == "cxchgweak"; let mut dst = args[0].immediate(); let mut cmp = args[1].immediate(); let mut src = args[2].immediate(); @@ -432,7 +426,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cmp = bx.ptrtoint(cmp, bx.type_isize()); src = bx.ptrtoint(src, bx.type_isize()); } - let pair = bx.atomic_cmpxchg(dst, cmp, src, order, failorder, weak); + let pair = bx.atomic_cmpxchg(dst, cmp, src, parse_ordering(bx, success), parse_ordering(bx, failure), weak); let val = bx.extract_value(pair, 0); let success = bx.extract_value(pair, 1); let val = bx.from_immediate(val); @@ -460,11 +454,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let llty = bx.type_isize(); let ptr_llty = bx.type_ptr_to(llty); source = bx.pointercast(source, ptr_llty); - let result = bx.atomic_load(llty, source, order, size); + let result = bx.atomic_load(llty, source, parse_ordering(bx, ordering), size); // ... and then cast the result back to a pointer bx.inttoptr(result, bx.backend_type(layout)) } else { - bx.atomic_load(bx.backend_type(layout), source, order, size) + bx.atomic_load(bx.backend_type(layout), source, parse_ordering(bx, ordering), size) } } else { return invalid_monomorphization(ty); @@ -484,7 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ptr = bx.pointercast(ptr, ptr_llty); val = bx.ptrtoint(val, bx.type_isize()); } - bx.atomic_store(val, ptr, order, size); + bx.atomic_store(val, ptr, parse_ordering(bx, ordering), size); return; } else { return invalid_monomorphization(ty); @@ -492,12 +486,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } "fence" => { - bx.atomic_fence(order, SynchronizationScope::CrossThread); + bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::CrossThread); return; } "singlethreadfence" => { - bx.atomic_fence(order, SynchronizationScope::SingleThread); + bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::SingleThread); return; } @@ -519,9 +513,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() - || (ty.is_unsafe_ptr() && op == "xchg") - { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let mut ptr = args[0].immediate(); let mut val = args[1].immediate(); if ty.is_unsafe_ptr() { @@ -531,7 +523,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ptr = bx.pointercast(ptr, ptr_llty); val = bx.ptrtoint(val, bx.type_isize()); } - bx.atomic_rmw(atom_op, ptr, val, order) + bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) } else { return invalid_monomorphization(ty); } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 0c958de64fa1c..ec3f7a2156a4a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -2,7 +2,7 @@ use crate::traits::*; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable}; use rustc_symbol_mangling::typeid_for_fnabi; use rustc_target::abi::call::{FnAbi, PassMode}; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 2e655ae94cc8b..c612634fce2a6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -84,6 +84,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } + ConstValue::ZeroSized => { + let llval = bx.zst_to_backend(bx.immediate_backend_type(layout)); + OperandValue::Immediate(llval) + } ConstValue::Slice { data, start, end } => { let Abi::ScalarPair(a_scalar, _) = layout.abi else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 5b88635982f54..421d6f807ae8e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -204,6 +204,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } /// Obtain the actual discriminant of a value. + #[instrument(level = "trace", skip(bx))] pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>( self, bx: &mut Bx, @@ -410,6 +411,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { downcast } + pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>( + &self, + bx: &mut Bx, + ty: Ty<'tcx>, + ) -> Self { + let mut downcast = *self; + downcast.layout = bx.cx().layout_of(ty); + + // Cast to the appropriate type. + let variant_ty = bx.cx().backend_type(downcast.layout); + downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty)); + + downcast + } + pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { bx.lifetime_start(self.llval, self.layout.size); } @@ -420,12 +436,12 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + #[instrument(level = "trace", skip(self, bx))] pub fn codegen_place( &mut self, bx: &mut Bx, place_ref: mir::PlaceRef<'tcx>, ) -> PlaceRef<'tcx, Bx::Value> { - debug!("codegen_place(place_ref={:?})", place_ref); let cx = self.cx; let tcx = self.cx.tcx(); @@ -458,6 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Field(ref field, _) => { cg_base.project_field(bx, field.index()) } + mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty), mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy(mir::Place::from(index)); let index = self.codegen_operand(bx, index); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 81c1897694ce6..26b9fbf442846 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,21 +8,20 @@ use crate::traits::*; use crate::MemFlags; use rustc_middle::mir; +use rustc_middle::mir::Operand; 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::{Abi, Int, Variants}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + #[instrument(level = "trace", skip(self, bx))] pub fn codegen_rvalue( &mut self, mut bx: Bx, dest: PlaceRef<'tcx, Bx::Value>, rvalue: &mir::Rvalue<'tcx>, ) -> Bx { - debug!("codegen_rvalue(dest.llval={:?}, rvalue={:?})", dest.llval, rvalue); - match *rvalue { mir::Rvalue::Use(ref operand) => { let cg_operand = self.codegen_operand(&mut bx, operand); @@ -125,7 +124,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Do not generate stores and GEPis for zero-sized fields. if !op.layout.is_zst() { let field_index = active_field_index.unwrap_or(i); - let field = dest.project_field(&mut bx, field_index); + let field = if let mir::AggregateKind::Array(_) = **kind { + let llindex = bx.cx().const_usize(field_index as u64); + dest.project_index(&mut bx, llindex) + } else { + dest.project_field(&mut bx, field_index) + }; op.val.store(&mut bx, field); } } @@ -213,6 +217,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { substs, ty::ClosureKind::FnOnce, ) + .expect("failed to normalize and resolve closure during codegen") .polymorphize(bx.cx().tcx()); OperandValue::Immediate(bx.cx().get_fn_addr(instance)) } @@ -284,74 +289,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { CastTy::from_ty(operand.layout.ty).expect("bad input type for cast"); let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast"); let ll_t_in = bx.cx().immediate_backend_type(operand.layout); - match operand.layout.variants { - Variants::Single { index } => { - if let Some(discr) = - operand.layout.ty.discriminant_for_variant(bx.tcx(), index) - { - let discr_layout = bx.cx().layout_of(discr.ty); - let discr_t = bx.cx().immediate_backend_type(discr_layout); - let discr_val = bx.cx().const_uint_big(discr_t, discr.val); - let discr_val = - bx.intcast(discr_val, ll_t_out, discr.ty.is_signed()); - - return ( - bx, - OperandRef { - val: OperandValue::Immediate(discr_val), - layout: cast, - }, - ); - } - } - Variants::Multiple { .. } => {} - } let llval = operand.immediate(); - let mut signed = false; - if let Abi::Scalar(scalar) = operand.layout.abi { - if let Int(_, s) = scalar.primitive() { - // We use `i1` for bytes that are always `0` or `1`, - // e.g., `#[repr(i8)] enum E { A, B }`, but we can't - // let LLVM interpret the `i1` as signed, because - // then `i1 1` (i.e., E::B) is effectively `i8 -1`. - signed = !scalar.is_bool() && s; - - if !scalar.is_always_valid(bx.cx()) - && scalar.valid_range(bx.cx()).end - >= scalar.valid_range(bx.cx()).start - { - // We want `table[e as usize ± k]` to not - // have bound checks, and this is the most - // convenient place to put the `assume`s. - if scalar.valid_range(bx.cx()).start > 0 { - let enum_value_lower_bound = bx.cx().const_uint_big( - ll_t_in, - scalar.valid_range(bx.cx()).start, - ); - let cmp_start = bx.icmp( - IntPredicate::IntUGE, - llval, - enum_value_lower_bound, - ); - bx.assume(cmp_start); - } - - let enum_value_upper_bound = bx - .cx() - .const_uint_big(ll_t_in, scalar.valid_range(bx.cx()).end); - let cmp_end = bx.icmp( - IntPredicate::IntULE, - llval, - enum_value_upper_bound, - ); - bx.assume(cmp_end); - } - } - } - let newval = match (r_t_in, r_t_out) { - (CastTy::Int(_), CastTy::Int(_)) => bx.intcast(llval, ll_t_out, signed), + (CastTy::Int(i), CastTy::Int(_)) => { + bx.intcast(llval, ll_t_out, i.is_signed()) + } (CastTy::Float, CastTy::Float) => { let srcsz = bx.cx().float_width(ll_t_in); let dstsz = bx.cx().float_width(ll_t_out); @@ -363,8 +306,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llval } } - (CastTy::Int(_), CastTy::Float) => { - if signed { + (CastTy::Int(i), CastTy::Float) => { + if i.is_signed() { bx.sitofp(llval, ll_t_out) } else { bx.uitofp(llval, ll_t_out) @@ -373,8 +316,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => { bx.pointercast(llval, ll_t_out) } - (CastTy::Int(_), CastTy::Ptr(_)) => { - let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed); + (CastTy::Int(i), CastTy::Ptr(_)) => { + let usize_llval = + bx.intcast(llval, bx.cx().type_isize(), i.is_signed()); bx.inttoptr(usize_llval, ll_t_out) } (CastTy::Float, CastTy::Int(IntTy::I)) => { @@ -401,6 +345,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ref) } + mir::Rvalue::CopyForDeref(place) => { + let operand = self.codegen_operand(&mut bx, &Operand::Copy(place)); + (bx, operand) + } mir::Rvalue::AddressOf(mutability, place) => { let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability }) @@ -755,6 +703,7 @@ 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::Ref(..) | + mir::Rvalue::CopyForDeref(..) | mir::Rvalue::AddressOf(..) | mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index d9ebfc3e87143..f452f29883f93 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -6,9 +6,8 @@ use crate::traits::BuilderMethods; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + #[instrument(level = "debug", skip(self, bx))] pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx { - debug!("codegen_statement(statement={:?})", statement); - self.set_debug_loc(&mut bx, statement.source_info); match statement.kind { mir::StatementKind::Assign(box (ref place, ref rvalue)) => { diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 1e53c73d1bb4a..779bd3ea278ec 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -59,7 +59,7 @@ impl<'tcx, T> Backend<'tcx> for T where pub trait CodegenBackend { fn init(&self, _sess: &Session) {} fn print(&self, _req: PrintRequest, _sess: &Session) {} - fn target_features(&self, _sess: &Session) -> Vec<Symbol> { + fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> { vec![] } fn print_passes(&self) {} diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 37f2bfd3c4fbd..1bbe10141fc7e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -221,7 +221,7 @@ pub trait BuilderMethods<'a, 'tcx>: assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double)); assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer); - if let Some(false) = self.cx().sess().opts.debugging_opts.saturating_float_casts { + if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts { return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) }; } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index c3519a24d5325..8a91d4735ba0d 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -2,7 +2,6 @@ use super::BackendTypes; use crate::mir::place::PlaceRef; use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_span::Symbol; use rustc_target::abi::{self, Size}; pub trait ConstMethods<'tcx>: BackendTypes { @@ -21,7 +20,7 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_u8(&self, i: u8) -> Self::Value; fn const_real(&self, t: Self::Type, val: f64) -> Self::Value; - fn const_str(&self, s: Symbol) -> (Self::Value, Self::Value); + fn const_str(&self, s: &str) -> (Self::Value, Self::Value); fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value; fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>; @@ -30,6 +29,7 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; + fn zst_to_backend(&self, llty: Self::Type) -> Self::Value; fn from_const_alloc( &self, layout: TyAndLayout<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 3eeb0138b37f7..eb81f43c3fe8c 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -82,12 +82,12 @@ impl<'tcx> ConstEvalErr<'tcx> { 'tcx: 'mir, { error.print_backtrace(); - let stacktrace = ecx.generate_stacktrace(); - ConstEvalErr { - error: error.into_kind(), - stacktrace, - span: span.unwrap_or_else(|| ecx.cur_span()), - } + let mut stacktrace = ecx.generate_stacktrace(); + // Filter out `requires_caller_location` frames. + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); + // If `span` is missing, use topmost remaining frame, or else the "root" span from `ecx.tcx`. + let span = span.or_else(|| stacktrace.first().map(|f| f.span)).unwrap_or(ecx.tcx.span); + ConstEvalErr { error: error.into_kind(), stacktrace, span } } pub fn struct_error( diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index b7e5e7aea49ce..f03ceb54830c8 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,7 +2,7 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, - Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, + Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ScalarMaybeUninit, StackPopCleanup, }; @@ -19,11 +19,9 @@ use rustc_target::abi::{self, Abi}; use std::borrow::Cow; use std::convert::TryInto; -pub fn note_on_undefined_behavior_error() -> &'static str { - "The rules on what exactly is undefined behavior aren't clear, \ +const NOTE_ON_UNDEFINED_BEHAVIOR_ERROR: &str = "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." -} + repository if you believe it should not be considered undefined behavior."; // Returns a pointer to where the result lives fn eval_body_using_ecx<'mir, 'tcx>( @@ -159,7 +157,7 @@ pub(super) fn op_to_const<'tcx>( "this MPlaceTy must come from a validated constant, thus we can assume the \ alignment is correct", ); - ConstValue::Scalar(Scalar::ZST) + ConstValue::ZeroSized } } }; @@ -167,6 +165,7 @@ pub(super) fn op_to_const<'tcx>( Ok(ref mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above Err(imm) => match *imm { + _ if imm.layout.is_zst() => ConstValue::ZeroSized, Immediate::Scalar(x) => match x { ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s), ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place()), @@ -191,6 +190,7 @@ pub(super) fn op_to_const<'tcx>( let len: usize = len.try_into().unwrap(); ConstValue::Slice { data, start, end: start + len } } + Immediate::Uninit => to_const_value(&op.assert_mem_place()), }, } } @@ -337,7 +337,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( } }; - Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg)) + Err(err.report_as_error(ecx.tcx.at(err.span), &msg)) } else { let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did); Err(err.report_as_lint( @@ -375,7 +375,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( ecx.tcx, "it is undefined behavior to use this value", |diag| { - diag.note(note_on_undefined_behavior_error()); + diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR); diag.note(&format!( "the raw bytes of the constant ({}", display_allocation( diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index ac529bf152f2b..29ab1d187719c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::AssertMessage; use rustc_session::Limit; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Align, Size}; -use rustc_target::spec::abi::Abi; +use rustc_target::spec::abi::Abi as CallAbi; use crate::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, @@ -263,7 +263,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - _abi: Abi, + _abi: CallAbi, args: &[OpTy<'tcx>], _dest: &PlaceTy<'tcx>, _ret: Option<mir::BasicBlock>, diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index a1d2e5cf3ef12..edc4c13b6e8f6 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -5,7 +5,6 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use rustc_target::abi::VariantIdx; use crate::interpret::{ intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta, @@ -91,83 +90,6 @@ pub(crate) fn eval_to_valtree<'tcx>( } } -/// Tries to destructure constants of type Array or Adt into the constants -/// of its fields. -pub(crate) fn try_destructure_const<'tcx>( - tcx: TyCtxt<'tcx>, - const_: ty::Const<'tcx>, -) -> Option<ty::DestructuredConst<'tcx>> { - if let ty::ConstKind::Value(valtree) = const_.kind() { - let branches = match valtree { - ty::ValTree::Branch(b) => b, - _ => return None, - }; - - let (fields, variant) = match const_.ty().kind() { - ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { - // construct the consts for the elements of the array/slice - let field_consts = branches - .iter() - .map(|b| { - tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty }) - }) - .collect::<Vec<_>>(); - debug!(?field_consts); - - (field_consts, None) - } - ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"), - ty::Adt(def, substs) => { - let variant_idx = if def.is_enum() { - VariantIdx::from_u32(branches[0].unwrap_leaf().try_to_u32().ok()?) - } else { - VariantIdx::from_u32(0) - }; - let fields = &def.variant(variant_idx).fields; - let mut field_consts = Vec::with_capacity(fields.len()); - - // Note: First element inValTree corresponds to variant of enum - let mut valtree_idx = if def.is_enum() { 1 } else { 0 }; - for field in fields { - let field_ty = field.ty(tcx, substs); - let field_valtree = branches[valtree_idx]; // first element of branches is variant - let field_const = tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Value(field_valtree), - ty: field_ty, - }); - field_consts.push(field_const); - valtree_idx += 1; - } - debug!(?field_consts); - - (field_consts, Some(variant_idx)) - } - ty::Tuple(elem_tys) => { - let fields = elem_tys - .iter() - .enumerate() - .map(|(i, elem_ty)| { - let elem_valtree = branches[i]; - tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Value(elem_valtree), - ty: elem_ty, - }) - }) - .collect::<Vec<_>>(); - - (fields, None) - } - _ => bug!("cannot destructure constant {:?}", const_), - }; - - let fields = tcx.arena.alloc_from_iter(fields.into_iter()); - - Some(ty::DestructuredConst { variant, fields }) - } else { - None - } -} - #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant<'tcx>( tcx: TyCtxt<'tcx>, @@ -225,7 +147,6 @@ pub(crate) fn deref_mir_constant<'tcx>( let ty = match mplace.meta { MemPlaceMeta::None => mplace.layout.ty, - MemPlaceMeta::Poison => bug!("poison metadata in `deref_mir_constant`: {:#?}", mplace), // In case of unsized types, figure out the real type behind. MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { ty::Str => bug!("there's no sized equivalent of a `str`"), diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 4849a07e3b4f4..8fff4571d127c 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -272,7 +272,7 @@ pub fn valtree_to_const_value<'tcx>( match ty.kind() { ty::FnDef(..) => { assert!(valtree.unwrap_branch().is_empty()); - ConstValue::Scalar(Scalar::ZST) + ConstValue::ZeroSized } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree { ty::ValTree::Leaf(scalar_int) => ConstValue::Scalar(Scalar::Int(scalar_int)), @@ -344,18 +344,14 @@ fn valtree_into_mplace<'tcx>( match ty.kind() { ty::FnDef(_, _) => { - ecx.write_immediate( - Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)), - &(*place).into(), - ) - .unwrap(); + ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap(); } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { let scalar_int = valtree.unwrap_leaf(); debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place); ecx.write_immediate( Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())), - &(*place).into(), + &place.into(), ) .unwrap(); } @@ -382,7 +378,7 @@ fn valtree_into_mplace<'tcx>( }; debug!(?imm); - ecx.write_immediate(imm, &(*place).into()).unwrap(); + ecx.write_immediate(imm, &place.into()).unwrap(); } ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => { let branches = valtree.unwrap_branch(); @@ -440,7 +436,7 @@ fn valtree_into_mplace<'tcx>( let offset = place_adjusted.layout.fields.offset(i); place - .offset( + .offset_with_meta( offset, MemPlaceMeta::Meta(Scalar::from_machine_usize( num_elems as u64, @@ -464,11 +460,11 @@ fn valtree_into_mplace<'tcx>( if let Some(variant_idx) = variant_idx { // don't forget filling the place with the discriminant of the enum - ecx.write_discriminant(variant_idx, &(*place).into()).unwrap(); + ecx.write_discriminant(variant_idx, &place.into()).unwrap(); } debug!("dump of place after writing discriminant:"); - dump_place(ecx, (*place).into()); + dump_place(ecx, place.into()); } _ => bug!("shouldn't have created a ValTree for {:?}", ty), } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs new file mode 100644 index 0000000000000..a463fe7b970f4 --- /dev/null +++ b/compiler/rustc_const_eval/src/errors.rs @@ -0,0 +1,89 @@ +use rustc_hir::ConstContext; +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[error(const_eval::unstable_in_stable)] +pub(crate) struct UnstableInStable { + pub gate: String, + #[primary_span] + pub span: Span, + #[suggestion( + const_eval::unstable_sugg, + code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", + applicability = "has-placeholders" + )] + #[suggestion( + const_eval::bypass_sugg, + code = "#[rustc_allow_const_fn_unstable({gate})]\n", + applicability = "has-placeholders" + )] + pub attr_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::thread_local_access, code = "E0625")] +pub(crate) struct NonConstOpErr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::static_access, code = "E0013")] +#[help] +pub(crate) struct StaticAccessErr { + #[primary_span] + pub span: Span, + pub kind: ConstContext, + #[note(const_eval::teach_note)] + #[help(const_eval::teach_help)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::raw_ptr_to_int)] +#[note] +#[note(const_eval::note2)] +pub(crate) struct RawPtrToIntErr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::raw_ptr_comparison)] +#[note] +pub(crate) struct RawPtrComparisonErr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::panic_non_str)] +pub(crate) struct PanicNonStrErr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::mut_deref, code = "E0658")] +pub(crate) struct MutDerefErr { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::transient_mut_borrow, code = "E0658")] +pub(crate) struct TransientMutBorrowErr { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} + +#[derive(SessionDiagnostic)] +#[error(const_eval::transient_mut_borrow_raw, code = "E0658")] +pub(crate) struct TransientMutBorrowErrRaw { + #[primary_span] + pub span: Span, + pub kind: ConstContext, +} diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index fb484fba9fd06..5d598b65c7224 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::CastKind; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut}; -use rustc_target::abi::{Integer, Variants}; +use rustc_target::abi::Integer; use rustc_type_ir::sty::TyKind::*; use super::{ @@ -100,7 +100,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { def_id, substs, ty::ClosureKind::FnOnce, - ); + ) + .ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.create_fn_alloc_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } @@ -127,12 +128,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Float(FloatTy::F64) => { return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into()); } - // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that - // are represented as integers. + // The rest is integer/pointer-"like", including fn ptr casts _ => assert!( src.layout.ty.is_bool() || src.layout.ty.is_char() - || src.layout.ty.is_enum() || src.layout.ty.is_integral() || src.layout.ty.is_any_ptr(), "Unexpected cast from type {:?}", @@ -142,25 +141,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # First handle non-scalar source values. - // Handle cast from a ZST enum (0 or 1 variants). - match src.layout.variants { - Variants::Single { index } => { - if src.layout.abi.is_uninhabited() { - // This is dead code, because an uninhabited enum is UB to - // instantiate. - throw_ub!(Unreachable); - } - if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { - assert!(src.layout.is_zst()); - let discr_layout = self.layout_of(discr.ty)?; - - let scalar = Scalar::from_uint(discr.val, discr_layout.layout.size()); - return Ok(self.cast_from_int_like(scalar, discr_layout, cast_ty)?.into()); - } - } - Variants::Multiple { .. } => {} - } - // Handle casting any ptr to raw ptr (might be a fat ptr). if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { let dest_layout = self.layout_of(cast_ty)?; @@ -173,7 +153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(dest_layout.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::ScalarPair(data, _) => Ok(data.check_init()?.into()), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({:?} -> {:?})", @@ -181,6 +161,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src.layout.ty, cast_ty ), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; } } @@ -202,7 +183,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr = self.scalar_to_ptr(scalar)?; match ptr.into_pointer_or_addr() { Ok(ptr) => M::expose_ptr(self, ptr)?, - Err(_) => {} // do nothing, exposing an invalid pointer has no meaning + Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } @@ -366,22 +347,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); - if def_a.is_box() || def_b.is_box() { - if !def_a.is_box() || !def_b.is_box() { - span_bug!( - self.cur_span(), - "invalid unsizing between {:?} -> {:?}", - src.layout.ty, - cast_ty.ty - ); - } - return self.unsize_into_ptr( - src, - dest, - src.layout.ty.boxed_ty(), - cast_ty.ty.boxed_ty(), - ); - } // unsizing of generic struct with pointer fields // Example: `Arc<T>` -> `Arc<Trait>` @@ -394,7 +359,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let src_field = self.operand_field(src, i)?; let dst_field = self.place_field(dest, i)?; if src_field.layout.ty == cast_ty_field.ty { - self.copy_op(&src_field, &dst_field)?; + self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?; } else { self.unsize_into(&src_field, cast_ty_field, &dst_field)?; } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 1c1bbd370bd49..bacf5d5a59f2a 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::layout::{ use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, }; -use rustc_mir_dataflow::storage::always_live_locals; +use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_query_system::ich::StableHashingContext; use rustc_session::Limit; use rustc_span::{Pos, Span}; @@ -112,6 +112,8 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> { /// The locals are stored as `Option<Value>`s. /// `None` represents a local that is currently dead, while a live local /// can either directly contain `Scalar` or refer to some part of an `Allocation`. + /// + /// Do *not* access this directly; always go through the machine hook! pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>, /// The span of the `tracing` crate is stored here. @@ -179,10 +181,6 @@ pub struct LocalState<'tcx, Tag: Provenance = AllocId> { pub enum LocalValue<Tag: Provenance = AllocId> { /// This local is not currently alive, and cannot be used at all. Dead, - /// This local is alive but not yet allocated. It cannot be read from or have its address taken, - /// and will be allocated on the first write. This is to support unsized locals, where we cannot - /// know their size in advance. - Unallocated, /// A normal, live local. /// Mostly for convenience, we re-use the `Operand` type here. /// This is an optimization over just always having a pointer here; @@ -196,12 +194,10 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { /// /// Note: This may only be invoked from the `Machine::access_local` hook and not from /// anywhere else. You may be invalidating machine invariants if you do! - pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> { - match self.value { - LocalValue::Dead => throw_ub!(DeadLocal), - LocalValue::Unallocated => { - bug!("The type checker should prevent reading from a never-written local") - } + #[inline] + pub fn access(&self) -> InterpResult<'tcx, &Operand<Tag>> { + match &self.value { + LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? LocalValue::Live(val) => Ok(val), } } @@ -211,15 +207,11 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> { /// /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from /// anywhere else. You may be invalidating machine invariants if you do! - pub fn access_mut( - &mut self, - ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> { - match self.value { - LocalValue::Dead => throw_ub!(DeadLocal), - LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), - ref mut local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Unallocated) => { - Ok(Ok(local)) - } + #[inline] + pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Tag>> { + match &mut self.value { + LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? + LocalValue::Live(val) => Ok(val), } } } @@ -428,11 +420,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn cur_span(&self) -> Span { - self.stack() - .iter() - .rev() - .find(|frame| !frame.instance.def.requires_caller_location(*self.tcx)) - .map_or(self.tcx.span, |f| f.current_span()) + // This deliberately does *not* honor `requires_caller_location` since it is used for much + // more than just panics. + self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } #[inline(always)] @@ -712,16 +702,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { })?; } - // Locals are initially unallocated. - let dummy = LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) }; + // Most locals are initially dead. + let dummy = LocalState { value: LocalValue::Dead, layout: Cell::new(None) }; let mut locals = IndexVec::from_elem(dummy, &body.local_decls); - // Now mark those locals as dead that we do not want to initialize - // Mark locals that use `Storage*` annotations as dead on function entry. - let always_live = always_live_locals(self.body()); + // Now mark those locals as live that have no `Storage*` annotations. + let always_live = always_storage_live_locals(self.body()); for local in locals.indices() { - if !always_live.contains(local) { - locals[local].value = LocalValue::Dead; + if always_live.contains(local) { + locals[local].value = LocalValue::Live(Operand::Immediate(Immediate::Uninit)); } } // done @@ -793,7 +782,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if unwinding { "during unwinding" } else { "returning from function" } ); - // Sanity check `unwinding`. + // Check `unwinding`. assert_eq!( unwinding, match self.frame().loc { @@ -801,51 +790,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(_) => true, } ); - if unwinding && self.frame_idx() == 0 { throw_ub_format!("unwinding past the topmost frame of the stack"); } - let frame = - self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); - - if !unwinding { - let op = self.access_local(&frame, mir::RETURN_PLACE, None)?; - self.copy_op_transmute(&op, &frame.return_place)?; - trace!("{:?}", self.dump_place(*frame.return_place)); - } - - let return_to_block = frame.return_to_block; - - // Now where do we jump next? + // Copy return value. Must of course happen *before* we deallocate the locals. + let copy_ret_result = if !unwinding { + let op = self + .local_to_op(self.frame(), mir::RETURN_PLACE, None) + .expect("return place should always be live"); + let dest = self.frame().return_place; + let err = self.copy_op(&op, &dest, /*allow_transmute*/ true); + trace!("return value: {:?}", self.dump_place(*dest)); + // We delay actually short-circuiting on this error until *after* the stack frame is + // popped, since we want this error to be attributed to the caller, whose type defines + // this transmute. + err + } else { + Ok(()) + }; + // Cleanup: deallocate locals. // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. - // In that case, we return early. We also avoid validation in that case, - // because this is CTFE and the final value will be thoroughly validated anyway. + // We do this while the frame is still on the stack, so errors point to the callee. + let return_to_block = self.frame().return_to_block; let cleanup = match return_to_block { StackPopCleanup::Goto { .. } => true, StackPopCleanup::Root { cleanup, .. } => cleanup, }; + if cleanup { + // We need to take the locals out, since we need to mutate while iterating. + let locals = mem::take(&mut self.frame_mut().locals); + for local in &locals { + self.deallocate_local(local.value)?; + } + } + + // All right, now it is time to actually pop the frame. + // Note that its locals are gone already, but that's fine. + let frame = + self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); + // Report error from return value copy, if any. + copy_ret_result?; + // If we are not doing cleanup, also skip everything else. if !cleanup { assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); assert!(!unwinding, "tried to skip cleanup during unwinding"); - // Leak the locals, skip validation, skip machine hook. + // Skip machine hook. return Ok(()); } - - trace!("locals: {:#?}", frame.locals); - - // Cleanup: deallocate all locals that are backed by an allocation. - for local in &frame.locals { - self.deallocate_local(local.value)?; - } - if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump { // The hook already did everything. - // We want to skip the `info!` below, hence early return. return Ok(()); } + // Normal return, figure out where to jump. if unwinding { // Follow the unwind edge. @@ -876,7 +875,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); trace!("{:?} is now live", local); - let local_val = LocalValue::Unallocated; + let local_val = LocalValue::Live(Operand::Immediate(Immediate::Uninit)); // StorageLive expects the local to be dead, and marks it live. let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); if !matches!(old, LocalValue::Dead) { @@ -939,12 +938,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[must_use] pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> { let mut frames = Vec::new(); - for frame in self - .stack() - .iter() - .rev() - .skip_while(|frame| frame.instance.def.requires_caller_location(*self.tcx)) - { + // This deliberately does *not* honor `requires_caller_location` since it is used for much + // more than just panics. + for frame in self.stack().iter().rev() { let lint_root = frame.current_source_info().and_then(|source_info| { match &frame.body.source_scopes[source_info.scope].local_data { mir::ClearCrossCrate::Set(data) => Some(data.lint_root), @@ -982,15 +978,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug match self.ecx.stack()[frame].locals[local].value { LocalValue::Dead => write!(fmt, " is dead")?, - LocalValue::Unallocated => write!(fmt, " is unallocated")?, + LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => { + write!(fmt, " is uninitialized")? + } LocalValue::Live(Operand::Indirect(mplace)) => { write!( fmt, - " by align({}){} ref {:?}:", - mplace.align.bytes(), + " by {} ref {:?}:", match mplace.meta { MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), - MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), + MemPlaceMeta::None => String::new(), }, mplace.ptr, )?; @@ -1016,13 +1013,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect())) } Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) { - Some(alloc_id) => write!( - fmt, - "by align({}) ref {:?}: {:?}", - mplace.align.bytes(), - mplace.ptr, - self.ecx.dump_alloc(alloc_id) - ), + Some(alloc_id) => { + write!(fmt, "by ref {:?}: {:?}", mplace.ptr, self.ecx.dump_alloc(alloc_id)) + } ptr => write!(fmt, " integral by ref: {:?}", ptr), }, } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 1fda60c021eed..7616e7a63d107 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -168,13 +168,56 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory mplace: &MPlaceTy<'tcx>, fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>, ) -> InterpResult<'tcx> { - // ZSTs cannot contain pointers, so we can skip them. - if mplace.layout.is_zst() { + // We want to walk the aggregate to look for references to intern. While doing that we + // also need to take special care of interior mutability. + // + // As an optimization, however, if the allocation does not contain any references: we don't + // need to do the walk. It can be costly for big arrays for example (e.g. issue #93215). + let is_walk_needed = |mplace: &MPlaceTy<'tcx>| -> InterpResult<'tcx, bool> { + // ZSTs cannot contain pointers, we can avoid the interning walk. + if mplace.layout.is_zst() { + return Ok(false); + } + + // Now, check whether this allocation could contain references. + // + // Note, this check may sometimes not be cheap, so we only do it when the walk we'd like + // to avoid could be expensive: on the potentially larger types, arrays and slices, + // rather than on all aggregates unconditionally. + if matches!(mplace.layout.ty.kind(), ty::Array(..) | ty::Slice(..)) { + let Some((size, align)) = self.ecx.size_and_align_of_mplace(&mplace)? else { + // We do the walk if we can't determine the size of the mplace: we may be + // dealing with extern types here in the future. + return Ok(true); + }; + + // If there are no relocations in this allocation, it does not contain references + // that point to another allocation, and we can avoid the interning walk. + if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? { + if !alloc.has_relocations() { + return Ok(false); + } + } else { + // We're encountering a ZST here, and can avoid the walk as well. + return Ok(false); + } + } + + // In the general case, we do the walk. + Ok(true) + }; + + // If this allocation contains no references to intern, we avoid the potentially costly + // walk. + // + // We can do this before the checks for interior mutability below, because only references + // are relevant in that situation, and we're checking if there are any here. + if !is_walk_needed(mplace)? { return Ok(()); } if let Some(def) = mplace.layout.ty.ty_adt_def() { - if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() { + if def.is_unsafe_cell() { // We are crossing over an `UnsafeCell`, we can mutate again. This means that // References we encounter inside here are interned as pointing to mutable // allocations. @@ -195,7 +238,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory let tcx = self.ecx.tcx; let ty = mplace.layout.ty; if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() { - let value = self.ecx.read_immediate(&(*mplace).into())?; + let value = self.ecx.read_immediate(&mplace.into())?; let mplace = self.ecx.ref_to_mplace(&value)?; assert_eq!(mplace.layout.ty, referenced_ty); // Handle trait object vtables. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index e51c51cf45e5e..3039b10373d8c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -132,8 +132,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Some(p) => p, }; - // Keep the patterns in this match ordered the same as the list in - // `src/librustc_middle/ty/constness.rs` match intrinsic_name { sym::caller_location => { let span = self.find_closest_untracked_caller_location(); @@ -174,7 +172,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest)?; + self.copy_op(&val, dest, /*allow_transmute*/ false)?; } sym::ctpop @@ -217,7 +215,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::mul_with_overflow => BinOp::Mul, _ => bug!(), }; - self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?; + self.binop_with_overflow( + bin_op, /*force_overflow_checks*/ true, &lhs, &rhs, dest, + )?; } sym::saturating_add | sym::saturating_sub => { let l = self.read_immediate(&args[0])?; @@ -392,7 +392,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::transmute => { - self.copy_op_transmute(&args[0], dest)?; + self.copy_op(&args[0], dest, /*allow_transmute*/ true)?; } sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { let ty = instance.substs.type_at(0); @@ -415,7 +415,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { && !layout.might_permit_raw_init( self, InitKind::Zero, - self.tcx.sess.opts.debugging_opts.strict_init_checks, + self.tcx.sess.opts.unstable_opts.strict_init_checks, ) { M::abort( @@ -430,7 +430,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { && !layout.might_permit_raw_init( self, InitKind::Uninit, - self.tcx.sess.opts.debugging_opts.strict_init_checks, + self.tcx.sess.opts.unstable_opts.strict_init_checks, ) { M::abort( @@ -459,7 +459,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let place = self.mplace_index(&dest, i)?; let value = if i == index { *elem } else { self.mplace_index(&input, i)?.into() }; - self.copy_op(&value, &place.into())?; + self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?; } } sym::simd_extract => { @@ -471,11 +471,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { index, input_len ); - self.copy_op(&self.mplace_index(&input, index)?.into(), dest)?; + self.copy_op( + &self.mplace_index(&input, index)?.into(), + dest, + /*allow_transmute*/ false, + )?; } sym::likely | sym::unlikely | sym::black_box => { // These just return their argument - self.copy_op(&args[0], dest)?; + self.copy_op(&args[0], dest, /*allow_transmute*/ false)?; } sym::assume => { let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?; 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 23ae2db6438c6..14fde2c305e96 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -80,7 +80,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { line: u32, col: u32, ) -> MPlaceTy<'tcx, M::PointerTag> { - let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail; + let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail; let file = if loc_details.file { self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not) } else { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index c18ac84171d69..7f8eea94aeeda 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -10,12 +10,11 @@ use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_target::abi::Size; -use rustc_target::spec::abi::Abi; +use rustc_target::spec::abi::Abi as CallAbi; use super::{ AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - LocalValue, MemPlace, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, - StackPopUnwind, + MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, }; /// Data returned by Machine::stack_pop, @@ -139,11 +138,14 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce integers and floats not having provenance. fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - /// Whether function calls should be [ABI](Abi)-checked. + /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { true } + /// Whether CheckedBinOp MIR statements should actually check for overflow. + fn checked_binop_checks_overflow(_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 /// constants, ... @@ -167,7 +169,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - abi: Abi, + abi: CallAbi, args: &[OpTy<'tcx, Self::PointerTag>], destination: &PlaceTy<'tcx, Self::PointerTag>, target: Option<mir::BasicBlock>, @@ -179,7 +181,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn call_extra_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Self::ExtraFnVal, - abi: Abi, + abi: CallAbi, args: &[OpTy<'tcx, Self::PointerTag>], destination: &PlaceTy<'tcx, Self::PointerTag>, target: Option<mir::BasicBlock>, @@ -223,11 +225,13 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Since reading a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. #[inline] - fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + fn access_local<'a>( + frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: mir::Local, - ) -> InterpResult<'tcx, Operand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a Operand<Self::PointerTag>> + where + 'tcx: 'mir, + { frame.locals[local].access() } @@ -239,7 +243,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: mir::Local, - ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>> + ) -> InterpResult<'tcx, &'a mut Operand<Self::PointerTag>> where 'tcx: 'mir, { @@ -415,12 +419,14 @@ pub trait Machine<'mir, 'tcx>: Sized { } /// Called immediately after a stack frame got popped, but before jumping back to the caller. + /// The `locals` have already been destroyed! fn after_stack_pop( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, - _unwinding: bool, + unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { // By default, we do not support unwinding from panics + assert!(!unwinding); Ok(StackPopJump::Normal) } } @@ -468,11 +474,16 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { true } + #[inline(always)] + fn checked_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { + true + } + #[inline(always)] fn call_extra_fn( _ecx: &mut InterpCx<$mir, $tcx, Self>, fn_val: !, - _abi: Abi, + _abi: CallAbi, _args: &[OpTy<$tcx>], _destination: &PlaceTy<$tcx, Self::PointerTag>, _target: Option<mir::BasicBlock>, @@ -513,7 +524,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _ecx: &InterpCx<$mir, $tcx, Self>, addr: u64, ) -> Pointer<Option<AllocId>> { - Pointer::new(None, Size::from_bytes(addr)) + Pointer::from_addr(addr) } #[inline(always)] @@ -523,7 +534,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { ) -> InterpResult<$tcx, Pointer<Option<AllocId>>> { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) - Ok(Pointer::new(None, Size::from_bytes(addr))) + Ok(Pointer::from_addr(addr)) } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index d46f2f38d3a65..509fe576893b7 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -56,15 +56,14 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> { } } -/// Used by `get_size_and_align` to indicate whether the allocation needs to be live. -#[derive(Debug, Copy, Clone)] -pub enum AllocCheck { - /// Allocation must be live and not a function pointer. - Dereferenceable, - /// Allocations needs to be live, but may be a function pointer. - Live, - /// Allocation may be dead. - MaybeDead, +/// The return value of `get_alloc_info` indicates the "kind" of the allocation. +pub enum AllocKind { + /// A regular live data allocation. + LiveData, + /// A function allocation (that fn ptrs point to). + Function, + /// A dead allocation. + Dead, } /// The value of a function pointer. @@ -277,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { kind: MemoryKind<M::MemoryKind>, ) -> InterpResult<'tcx> { let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?; - trace!("deallocating: {}", alloc_id); + trace!("deallocating: {alloc_id:?}"); if offset.bytes() != 0 { throw_ub_format!( @@ -290,10 +289,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Deallocating global memory -- always an error return Err(match self.tcx.get_global_alloc(alloc_id) { Some(GlobalAlloc::Function(..)) => { - err_ub_format!("deallocating {}, which is a function", alloc_id) + err_ub_format!("deallocating {alloc_id:?}, which is a function") } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_format!("deallocating {}, which is static memory", alloc_id) + err_ub_format!("deallocating {alloc_id:?}, which is static memory") } None => err_ub!(PointerUseAfterFree(alloc_id)), } @@ -303,21 +302,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { debug!(?alloc); if alloc.mutability == Mutability::Not { - throw_ub_format!("deallocating immutable allocation {}", alloc_id); + throw_ub_format!("deallocating immutable allocation {alloc_id:?}"); } if alloc_kind != kind { throw_ub_format!( - "deallocating {}, which is {} memory, using {} deallocation operation", - alloc_id, - alloc_kind, - kind + "deallocating {alloc_id:?}, which is {alloc_kind} memory, using {kind} deallocation operation" ); } if let Some((size, align)) = old_size_and_align { if size != alloc.size() || align != alloc.align { throw_ub_format!( - "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}", - alloc_id, + "incorrect layout on deallocation: {alloc_id:?} has size {} and alignment {}, but gave size {} and alignment {}", alloc.size().bytes(), alloc.align.bytes(), size.bytes(), @@ -360,8 +355,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { align, CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, tag| { - let (size, align) = - self.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?; Ok((size, align, (alloc_id, offset, tag))) }, ) @@ -379,15 +373,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| { - let check = match msg { - CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => { - AllocCheck::Dereferenceable - } - CheckInAllocMsg::PointerArithmeticTest - | CheckInAllocMsg::OffsetFromTest - | CheckInAllocMsg::InboundsTest => AllocCheck::Live, - }; - let (size, align) = self.get_alloc_size_and_align(alloc_id, check)?; + let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?; Ok((size, align, ())) })?; Ok(()) @@ -655,30 +641,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. - /// - /// If `liveness` is `AllocCheck::MaybeDead`, this function always returns `Ok`. - pub fn get_alloc_size_and_align( - &self, - id: AllocId, - liveness: AllocCheck, - ) -> InterpResult<'tcx, (Size, Align)> { + pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static // b) duplicate a global's allocation in miri if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - return Ok((alloc.size(), alloc.align)); + return (alloc.size(), alloc.align, AllocKind::LiveData); } // # Function pointers // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if self.get_fn_alloc(id).is_some() { - return if let AllocCheck::Dereferenceable = liveness { - // The caller requested no function pointers. - throw_ub!(DerefFunctionPointer(id)) - } else { - Ok((Size::ZERO, Align::ONE)) - }; + return (Size::ZERO, Align::ONE, AllocKind::Function); } // # Statics @@ -690,32 +665,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Use size and align of the type. let ty = self.tcx.type_of(did); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - Ok((layout.size, layout.align.abi)) + (layout.size, layout.align.abi, AllocKind::LiveData) } Some(GlobalAlloc::Memory(alloc)) => { // Need to duplicate the logic here, because the global allocations have // different associated types than the interpreter-local ones. let alloc = alloc.inner(); - Ok((alloc.size(), alloc.align)) + (alloc.size(), alloc.align, AllocKind::LiveData) } Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), // The rest must be dead. None => { - if let AllocCheck::MaybeDead = liveness { - // Deallocated pointers are allowed, we should be able to find - // them in the map. - Ok(*self - .memory - .dead_alloc_map - .get(&id) - .expect("deallocated pointers should all be recorded in `dead_alloc_map`")) - } else { - throw_ub!(PointerUseAfterFree(id)) - } + // Deallocated pointers are allowed, we should be able to find + // them in the map. + let (size, align) = *self + .memory + .dead_alloc_map + .get(&id) + .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); + (size, align, AllocKind::Dead) } } } + /// Obtain the size and alignment of a live allocation. + pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> { + let (size, align, kind) = self.get_alloc_info(id); + if matches!(kind, AllocKind::Dead) { + throw_ub!(PointerUseAfterFree(id)) + } + Ok((size, align)) + } + fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> { if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) { Some(FnVal::Other(*extra)) @@ -830,7 +811,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, continue; } - write!(fmt, "{}", id)?; + write!(fmt, "{id:?}")?; match self.ecx.memory.alloc_map.get(id) { Some(&(kind, ref alloc)) => { // normal alloc @@ -874,25 +855,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, /// Reading and writing. impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { + /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar( &mut self, range: AllocRange, val: ScalarMaybeUninit<Tag>, ) -> InterpResult<'tcx> { let range = self.range.subrange(range); - debug!( - "write_scalar in {} at {:#x}, size {}: {:?}", - self.alloc_id, - range.start.bytes(), - range.size.bytes(), - val - ); + debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); Ok(self .alloc .write_scalar(&self.tcx, range, val) .map_err(|e| e.to_interp_error(self.alloc_id))?) } + /// `offset` is relative to this allocation reference, not the base of the allocation. pub fn write_ptr_sized( &mut self, offset: Size, @@ -911,6 +888,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { } impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { + /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, range: AllocRange, @@ -921,24 +899,16 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { .alloc .read_scalar(&self.tcx, range, read_provenance) .map_err(|e| e.to_interp_error(self.alloc_id))?; - debug!( - "read_scalar in {} at {:#x}, size {}: {:?}", - self.alloc_id, - range.start.bytes(), - range.size.bytes(), - res - ); + debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id); Ok(res) } - pub fn read_integer( - &self, - offset: Size, - size: Size, - ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { - self.read_scalar(alloc_range(offset, size), /*read_provenance*/ false) + /// `range` is relative to this allocation reference, not the base of the allocation. + pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + self.read_scalar(range, /*read_provenance*/ false) } + /// `offset` is relative to this allocation reference, not the base of the allocation. pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { self.read_scalar( alloc_range(offset, self.tcx.data_layout().pointer_size), @@ -946,6 +916,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { ) } + /// `range` is relative to this allocation reference, not the base of the allocation. pub fn check_bytes( &self, range: AllocRange, @@ -957,6 +928,11 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr) .map_err(|e| e.to_interp_error(self.alloc_id))?) } + + /// Returns whether the allocation has relocations for the entire range of the `AllocRef`. + pub(crate) fn has_relocations(&self) -> bool { + self.alloc.has_relocations(&self.tcx, self.range) + } } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -1187,9 +1163,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr = self.scalar_to_ptr(scalar)?; match self.ptr_try_get_alloc_id(ptr) { Ok((alloc_id, offset, _)) => { - let (size, _align) = self - .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail"); + let (size, _align, _kind) = self.get_alloc_info(alloc_id); // If the pointer is out-of-bounds, it may be null. // Note that one-past-the-end (offset == size) is still inbounds, and never null. offset > size diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 2b73ad568e0ee..2e356f67bf36f 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -9,6 +9,7 @@ mod memory; mod operand; mod operator; mod place; +mod projection; mod step; mod terminator; mod traits; @@ -23,7 +24,7 @@ pub use self::eval_context::{ }; pub use self::intern::{intern_const_alloc_recursive, InternKind}; pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; -pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; +pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::validity::{CtfeValidationMode, RefTracking}; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 6b05a49575fd9..22dc1e80f13a8 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -1,7 +1,6 @@ //! Functions concerning immediate values and operands, and reading from operands. //! All high-level functions to read from memory work on operands as sources. -use std::convert::TryFrom; use std::fmt::Write; use rustc_hir::def::Namespace; @@ -10,12 +9,12 @@ use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty}; use rustc_middle::{mir, ty}; -use rustc_target::abi::{self, Abi, HasDataLayout, Size, TagEncoding}; +use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId, - InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, + alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId, + InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Place, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, }; @@ -28,8 +27,15 @@ use super::{ /// defined on `Immediate`, and do not have to work with a `Place`. #[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)] pub enum Immediate<Tag: Provenance = AllocId> { + /// A single scalar value (must have *initialized* `Scalar` ABI). + /// FIXME: we also currently often use this for ZST. + /// `ScalarMaybeUninit` should reject ZST, and we should use `Uninit` for them instead. Scalar(ScalarMaybeUninit<Tag>), + /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are + /// `Scalar::Initialized`). ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>), + /// A value of fully uninitialized memory. Can have and size and layout. + Uninit, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -71,27 +77,33 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> { } #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> { match self { Immediate::Scalar(val) => val, Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), + Immediate::Uninit => ScalarMaybeUninit::Uninit, } } #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> { self.to_scalar_or_uninit().check_init() } #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>) { match self { Immediate::ScalarPair(val1, val2) => (val1, val2), Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"), + Immediate::Uninit => (ScalarMaybeUninit::Uninit, ScalarMaybeUninit::Uninit), } } #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> { let (val1, val2) = self.to_scalar_or_uninit_pair(); Ok((val1.check_init()?, val2.check_init()?)) @@ -149,7 +161,10 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> { } Immediate::ScalarPair(a, b) => { // FIXME(oli-obk): at least print tuples and slices nicely - write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty,) + write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty) + } + Immediate::Uninit => { + write!(f, "uninit: {}", self.layout.ty) } } }) @@ -177,10 +192,18 @@ pub enum Operand<Tag: Provenance = AllocId> { pub struct OpTy<'tcx, Tag: Provenance = AllocId> { op: Operand<Tag>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for an `OpTy`! + /// `None` means "alignment does not matter since this is a by-value operand" + /// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`. + /// Also CTFE ignores alignment anyway, so this is for Miri only. + pub align: Option<Align>, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(OpTy<'_>, 80); +rustc_data_structures::static_assert_size!(OpTy<'_>, 88); impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { type Target = Operand<Tag>; @@ -193,21 +216,28 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { - OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout } + OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) } } } impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { #[inline(always)] fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { - OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout } + OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) } + } +} + +impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> { + #[inline(always)] + fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { + OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) } } } impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> { #[inline(always)] fn from(val: ImmTy<'tcx, Tag>) -> Self { - OpTy { op: Operand::Immediate(val.imm), layout: val.layout } + OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } } } @@ -222,6 +252,11 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { ImmTy { imm, layout } } + #[inline] + pub fn uninit(layout: TyAndLayout<'tcx>) -> Self { + ImmTy { imm: Immediate::Uninit, layout } + } + #[inline] pub fn try_from_uint(i: impl Into<u128>, layout: TyAndLayout<'tcx>) -> Option<Self> { Some(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) @@ -249,6 +284,51 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { } } +impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { + pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { + if self.layout.is_unsized() { + // There are no unsized immediates. + self.assert_mem_place().len(cx) + } else { + match self.layout.fields { + abi::FieldsShape::Array { count, .. } => Ok(count), + _ => bug!("len not supported on sized type {:?}", self.layout.ty), + } + } + } + + pub fn offset_with_meta( + &self, + offset: Size, + meta: MemPlaceMeta<Tag>, + layout: TyAndLayout<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + match self.try_as_mplace() { + Ok(mplace) => Ok(mplace.offset_with_meta(offset, meta, layout, cx)?.into()), + Err(imm) => { + assert!( + matches!(*imm, Immediate::Uninit), + "Scalar/ScalarPair cannot be offset into" + ); + assert!(!meta.has_meta()); // no place to store metadata here + // Every part of an uninit is uninit. + Ok(ImmTy::uninit(layout).into()) + } + } + } + + pub fn offset( + &self, + offset: Size, + layout: TyAndLayout<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + assert!(!layout.is_unsized()); + self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx) + } +} + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// Returns `None` if the layout does not permit loading this as a value. @@ -265,11 +345,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } let Some(alloc) = self.get_place_alloc(mplace)? else { - return Ok(Some(ImmTy { - // zero-sized type - imm: Scalar::ZST.into(), - layout: mplace.layout, - })); + // zero-sized type can be left uninit + return Ok(Some(ImmTy::uninit(mplace.layout))); }; // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. @@ -291,9 +368,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { s.is_ptr() || (number_may_have_provenance && size == self.pointer_size()) }; if let Some(s) = scalar_layout { - //FIXME(#96185): let size = s.size(self); - //FIXME(#96185): assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); - let size = mplace.layout.size; //FIXME(#96185): remove this line + let size = s.size(self); + assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); let scalar = alloc.read_scalar(alloc_range(Size::ZERO, size), read_provenance(s, size))?; return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })); @@ -337,6 +413,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This flag exists only for validity checking. /// /// This is an internal function that should not usually be used; call `read_immediate` instead. + /// ConstProp needs it, though. pub fn read_immediate_raw( &self, src: &OpTy<'tcx, M::PointerTag>, @@ -383,7 +460,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.scalar_to_ptr(self.read_scalar(op)?.check_init()?) } - // Turn the wide MPlace into a string (must already be dereferenced!) + /// Turn the wide MPlace into a string (must already be dereferenced!) pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.read_bytes_ptr(mplace.ptr, Size::from_bytes(len))?; @@ -391,144 +468,49 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(str) } - /// Projection functions - pub fn operand_field( - &self, - op: &OpTy<'tcx, M::PointerTag>, - field: usize, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let base = match op.try_as_mplace() { - Ok(ref mplace) => { - // We can reuse the mplace field computation logic for indirect operands. - let field = self.mplace_field(mplace, field)?; - return Ok(field.into()); - } - Err(value) => value, - }; - - let field_layout = base.layout.field(self, field); - let offset = base.layout.fields.offset(field); - // This makes several assumptions about what layouts we will encounter; we match what - // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). - let field_val: Immediate<_> = match (*base, base.layout.abi) { - // the field contains no information - _ if field_layout.is_zst() => Scalar::ZST.into(), - // the field covers the entire type - _ if field_layout.size == base.layout.size => { - assert!(match (base.layout.abi, field_layout.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => true, - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true, - _ => false, - }); - assert!(offset.bytes() == 0); - *base - } - // extract fields from types with `ScalarPair` ABI - (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { - assert!(matches!(field_layout.abi, Abi::Scalar(..))); - Immediate::from(if offset.bytes() == 0 { - debug_assert_eq!(field_layout.size, a.size(self)); - a_val - } else { - debug_assert_eq!(offset, a.size(self).align_to(b.align(self).abi)); - debug_assert_eq!(field_layout.size, b.size(self)); - b_val - }) - } - _ => span_bug!( - self.cur_span(), - "invalid field access on immediate {}, layout {:#?}", - base, - base.layout - ), - }; - - Ok(OpTy { op: Operand::Immediate(field_val), layout: field_layout }) - } - - pub fn operand_index( - &self, - op: &OpTy<'tcx, M::PointerTag>, - index: u64, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - if let Ok(index) = usize::try_from(index) { - // We can just treat this as a field. - self.operand_field(op, index) - } else { - // Indexing into a big array. This must be an mplace. - let mplace = op.assert_mem_place(); - Ok(self.mplace_index(&mplace, index)?.into()) - } - } - - pub fn operand_downcast( - &self, - op: &OpTy<'tcx, M::PointerTag>, - variant: VariantIdx, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok(match op.try_as_mplace() { - Ok(ref mplace) => self.mplace_downcast(mplace, variant)?.into(), - Err(..) => { - // Downcasts only change the layout. - // (In particular, no check about whether this is even the active variant -- that's by design, - // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) - let layout = op.layout.for_variant(self, variant); - OpTy { layout, ..*op } - } - }) - } - - #[instrument(skip(self), level = "debug")] - pub fn operand_projection( - &self, - base: &OpTy<'tcx, M::PointerTag>, - proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { - Field(field, _) => self.operand_field(base, field.index())?, - Downcast(_, variant) => self.operand_downcast(base, variant)?, - Deref => self.deref_operand(base)?.into(), - Subslice { .. } | ConstantIndex { .. } | Index(_) => { - // The rest should only occur as mplace, we do not use Immediates for types - // allowing such operations. This matches place_projection forcing an allocation. - let mplace = base.assert_mem_place(); - self.mplace_projection(&mplace, proj_elem)?.into() - } - }) - } - /// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements. /// Also returns the number of elements. + /// + /// Can (but does not always) trigger UB if `op` is uninitialized. pub fn operand_to_simd( &self, - base: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { // Basically we just transmute this place into an array following simd_size_and_type. // This only works in memory, but repr(simd) types should never be immediates anyway. - assert!(base.layout.ty.is_simd()); - self.mplace_to_simd(&base.assert_mem_place()) + assert!(op.layout.ty.is_simd()); + match op.try_as_mplace() { + Ok(mplace) => self.mplace_to_simd(&mplace), + Err(imm) => match *imm { + Immediate::Uninit => { + throw_ub!(InvalidUninitBytes(None)) + } + Immediate::Scalar(..) | Immediate::ScalarPair(..) => { + bug!("arrays/slices can never have Scalar/ScalarPair layout") + } + }, + } } /// Read from a local. Will not actually access the local if reading from a ZST. /// Will not access memory, instead an indirect `Operand` is returned. /// /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an - /// OpTy from a local - pub fn access_local( + /// OpTy from a local. + pub fn local_to_op( &self, - frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let layout = self.layout_of_local(frame, local, layout)?; let op = if layout.is_zst() { - // Do not read from ZST, they might not be initialized - Operand::Immediate(Scalar::ZST.into()) + // Bypass `access_local` (helps in ConstProp) + Operand::Immediate(Immediate::Uninit) } else { - M::access_local(&self, frame, local)? + *M::access_local(frame, local)? }; - Ok(OpTy { op, layout }) + Ok(OpTy { op, layout, align: Some(layout.align.abi) }) } /// Every place can be read from, so we can turn them into an operand. @@ -542,40 +524,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let op = match **place { Place::Ptr(mplace) => Operand::Indirect(mplace), Place::Local { frame, local } => { - *self.access_local(&self.stack()[frame], local, None)? + *self.local_to_op(&self.stack()[frame], local, None)? } }; - Ok(OpTy { op, layout: place.layout }) + Ok(OpTy { op, layout: place.layout, align: Some(place.align) }) } /// Evaluate a place with the goal of reading from it. This lets us sometimes /// avoid allocations. pub fn eval_place_to_op( &self, - place: mir::Place<'tcx>, + mir_place: mir::Place<'tcx>, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. - let layout = if place.projection.is_empty() { layout } else { None }; - - let base_op = self.access_local(self.frame(), place.local, layout)?; + let layout = if mir_place.projection.is_empty() { layout } else { None }; - let op = place - .projection - .iter() - .try_fold(base_op, |op, elem| self.operand_projection(&op, elem))?; + let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?; + // Using `try_fold` turned out to be bad for performance, hence the loop. + for elem in mir_place.projection.iter() { + op = self.operand_projection(&op, elem)? + } trace!("eval_place_to_op: got {:?}", *op); // Sanity-check the type we ended up with. - debug_assert!(mir_assign_valid_types( - *self.tcx, - self.param_env, - self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( - place.ty(&self.frame().body.local_decls, *self.tcx).ty - )?)?, - op.layout, - )); + debug_assert!( + mir_assign_valid_types( + *self.tcx, + self.param_env, + self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( + mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty + )?)?, + op.layout, + ), + "eval_place of a MIR place with type {:?} produced an interpreter operand with type {:?}", + mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, + op.layout.ty, + ); Ok(op) } @@ -596,11 +582,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Constant(ref constant) => { let val = self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?; + // This can still fail: // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all // checked yet. // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail. - self.mir_const_to_op(&val, layout)? } }; @@ -676,9 +662,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen. let ptr = self.global_base_pointer(Pointer::new(id, offset))?; - Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi)) + Operand::Indirect(MemPlace::from_ptr(ptr.into())) } ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()), + ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit), ConstValue::Slice { data, start, end } => { // We rely on mutability being set correctly in `data` to prevent writes // where none should happen. @@ -693,7 +680,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )) } }; - Ok(OpTy { op, layout }) + Ok(OpTy { op, layout, align: Some(layout.align.abi) }) } /// Read discriminant, return the runtime value as well as the variant index. diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 85ee88e9e474e..88999e3b47b5e 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -5,15 +5,20 @@ use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty}; +use rustc_target::abi::Abi; use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Applies the binary operation `op` to the two operands and writes a tuple of the result /// and a boolean signifying the potential overflow to the destination. + /// + /// `force_overflow_checks` indicates whether overflow checks should be done even when + /// `tcx.sess.overflow_checks()` is `false`. pub fn binop_with_overflow( &mut self, op: mir::BinOp, + force_overflow_checks: bool, left: &ImmTy<'tcx, M::PointerTag>, right: &ImmTy<'tcx, M::PointerTag>, dest: &PlaceTy<'tcx, M::PointerTag>, @@ -25,8 +30,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { "type mismatch for result of {:?}", op, ); - let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into()); - self.write_immediate(val, dest) + // As per https://github.com/rust-lang/rust/pull/98738, we always return `false` in the 2nd + // component when overflow checking is disabled. + let overflowed = + overflowed && (force_overflow_checks || M::checked_binop_checks_overflow(self)); + // Write the result to `dest`. + if let Abi::ScalarPair(..) = dest.layout.abi { + // We can use the optimized path and avoid `place_field` (which might do + // `force_allocation`). + let pair = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into()); + self.write_immediate(pair, dest)?; + } else { + assert!(self.tcx.sess.opts.unstable_opts.randomize_layout); + // With randomized layout, `(int, bool)` might cease to be a `ScalarPair`, so we have to + // do a component-wise write here. This code path is slower than the above because + // `place_field` will have to `force_allocate` locals here. + let val_field = self.place_field(&dest, 0)?; + self.write_scalar(val, &val_field)?; + let overflowed_field = self.place_field(&dest, 1)?; + self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?; + } + Ok(()) } /// Applies the binary operation `op` to the arguments and writes the result to the diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 3dbcba72baf3b..a29a1492c8ef3 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -2,21 +2,19 @@ //! into a place. //! All high-level functions to write to memory work on places as destinations. -use std::convert::TryFrom; use std::hash::Hash; use rustc_ast::Mutability; use rustc_macros::HashStable; use rustc_middle::mir; +use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout}; -use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; -use rustc_target::abi::{HasDataLayout, Size, VariantIdx, Variants}; +use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding, VariantIdx}; use super::{ alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, - ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, - Operand, Pointer, Provenance, Scalar, ScalarMaybeUninit, + ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand, + Pointer, Provenance, Scalar, ScalarMaybeUninit, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] @@ -26,11 +24,6 @@ pub enum MemPlaceMeta<Tag: Provenance = AllocId> { Meta(Scalar<Tag>), /// `Sized` types or unsized `extern type` None, - /// The address of this place may not be taken. This protects the `MemPlace` from coming from - /// a ZST Operand without a backing allocation and being converted to an integer address. This - /// should be impossible, because you can't take the address of an operand, but this is a second - /// protection layer ensuring that we don't mess up. - Poison, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -40,15 +33,16 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> { pub fn unwrap_meta(self) -> Scalar<Tag> { match self { Self::Meta(s) => s, - Self::None | Self::Poison => { + Self::None => { bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") } } } - fn has_meta(self) -> bool { + + pub fn has_meta(self) -> bool { match self { Self::Meta(_) => true, - Self::None | Self::Poison => false, + Self::None => false, } } } @@ -57,7 +51,6 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> { pub struct MemPlace<Tag: Provenance = AllocId> { /// The pointer can be a pure integer, with the `None` tag. pub ptr: Pointer<Option<Tag>>, - pub align: Align, /// Metadata for unsized places. Interpretation is up to the type. /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). @@ -65,7 +58,7 @@ pub struct MemPlace<Tag: Provenance = AllocId> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(MemPlace, 48); +rustc_data_structures::static_assert_size!(MemPlace, 40); #[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)] pub enum Place<Tag: Provenance = AllocId> { @@ -78,12 +71,17 @@ pub enum Place<Tag: Provenance = AllocId> { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Place, 56); +rustc_data_structures::static_assert_size!(Place, 48); #[derive(Copy, Clone, Debug)] pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> { place: Place<Tag>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for a `PlaceTy`! + pub align: Align, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -102,6 +100,11 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> { pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> { mplace: MemPlace<Tag>, pub layout: TyAndLayout<'tcx>, + /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: + /// it needs to have a different alignment than the field type would usually have. + /// So we represent this here with a separate field that "overwrites" `layout.align`. + /// This means `layout.align` should never be used for a `MPlaceTy`! + pub align: Align, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -118,14 +121,28 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> { impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self { - PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout } + PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align } + } +} + +impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { + #[inline(always)] + fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self { + PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } + } +} + +impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> { + #[inline(always)] + fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self { + PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align } } } impl<Tag: Provenance> MemPlace<Tag> { #[inline(always)] - pub fn from_ptr(ptr: Pointer<Option<Tag>>, align: Align) -> Self { - MemPlace { ptr, align, meta: MemPlaceMeta::None } + pub fn from_ptr(ptr: Pointer<Option<Tag>>) -> Self { + MemPlace { ptr, meta: MemPlaceMeta::None } } /// Adjust the provenance of the main pointer (metadata is unaffected). @@ -142,52 +159,73 @@ impl<Tag: Provenance> MemPlace<Tag> { MemPlaceMeta::Meta(meta) => { Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx).into(), meta.into()) } - MemPlaceMeta::Poison => bug!( - "MPlaceTy::dangling may never be used to produce a \ - place that will have the address of its pointee taken" - ), } } #[inline] - pub fn offset<'tcx>( + pub fn offset_with_meta<'tcx>( self, offset: Size, meta: MemPlaceMeta<Tag>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { - Ok(MemPlace { - ptr: self.ptr.offset(offset, cx)?, - align: self.align.restrict_for_offset(offset), - meta, - }) + Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta }) + } +} + +impl<Tag: Provenance> Place<Tag> { + /// Asserts that this points to some local variable. + /// Returns the frame idx and the variable idx. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) + pub fn assert_local(&self) -> (usize, mir::Local) { + match self { + Place::Local { frame, local } => (*frame, *local), + _ => bug!("assert_local: expected Place::Local, got {:?}", self), + } } } impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { - /// Produces a MemPlace that works for ZST but nothing else + /// Produces a MemPlace that works for ZST but nothing else. + /// Conceptually this is a new allocation, but it doesn't actually create an allocation so you + /// don't need to worry about memory leaks. #[inline] - pub fn dangling(layout: TyAndLayout<'tcx>) -> Self { + pub fn fake_alloc_zst(layout: TyAndLayout<'tcx>) -> Self { + assert!(layout.is_zst()); let align = layout.align.abi; - let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address - // `Poison` this to make sure that the pointer value `ptr` is never observable by the program. - MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } + let ptr = Pointer::from_addr(align.bytes()); // no provenance, absolute address + MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None }, layout, align } } #[inline] - pub fn offset( + pub fn offset_with_meta( &self, offset: Size, meta: MemPlaceMeta<Tag>, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { mplace: self.mplace.offset(offset, meta, cx)?, layout }) + Ok(MPlaceTy { + mplace: self.mplace.offset_with_meta(offset, meta, cx)?, + align: self.align.restrict_for_offset(offset), + layout, + }) + } + + pub fn offset( + &self, + offset: Size, + layout: TyAndLayout<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Self> { + assert!(!layout.is_unsized()); + self.offset_with_meta(offset, MemPlaceMeta::None, layout, cx) } #[inline] pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self { - MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout } + MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } } #[inline] @@ -196,10 +234,10 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { layout: TyAndLayout<'tcx>, meta: MemPlaceMeta<Tag>, ) -> Self { - let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi); + let mut mplace = MemPlace::from_ptr(ptr); mplace.meta = meta; - MPlaceTy { mplace, layout } + MPlaceTy { mplace, layout, align: layout.align.abi } } #[inline] @@ -214,7 +252,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> { // Go through the layout. There are lots of types that support a length, // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!) match self.layout.fields { - FieldsShape::Array { count, .. } => Ok(count), + abi::FieldsShape::Array { count, .. } => Ok(count), _ => bug!("len not supported on sized type {:?}", self.layout.ty), } } @@ -236,13 +274,15 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { /// read from the resulting mplace, not to get its address back. pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> { match **self { - Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), - Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout)), + Operand::Indirect(mplace) => { + Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() }) + } Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)), } } #[inline(always)] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> { @@ -250,27 +290,26 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> { } } -impl<Tag: Provenance> Place<Tag> { +impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { + /// A place is either an mplace or some local. #[inline] - pub fn assert_mem_place(self) -> MemPlace<Tag> { - match self { - Place::Ptr(mplace) => mplace, - _ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self), + pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, (usize, mir::Local)> { + match **self { + Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }), + Place::Local { frame, local } => Err((frame, local)), } } -} -impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> { - #[inline] + #[inline(always)] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { - MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout } + self.try_as_mplace().unwrap() } } -// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385 +// FIXME: Working around https://github.com/rust-lang/rust/issues/54385 impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> where - // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 Tag: Provenance + Eq + Hash + 'static, M: Machine<'mir, 'tcx, PointerTag = Tag>, { @@ -290,18 +329,13 @@ where let (ptr, meta) = match **val { Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None), Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; - let mplace = MemPlace { - ptr: self.scalar_to_ptr(ptr.check_init()?)?, - // We could use the run-time alignment here. For now, we do not, because - // the point of tracking the alignment here is to make sure that the *static* - // alignment information emitted with the loads is correct. The run-time - // alignment can only be more restrictive. - align: layout.align.abi, - meta, - }; - Ok(MPlaceTy { mplace, layout }) + let mplace = MemPlace { ptr: self.scalar_to_ptr(ptr.check_init()?)?, meta }; + // When deref'ing a pointer, the *static* alignment given by the type is what matters. + let align = layout.align.abi; + Ok(MPlaceTy { mplace, layout, align }) } /// Take an operand, representing a pointer, and dereference it to a place -- that @@ -354,315 +388,77 @@ where let (size, align) = self .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - assert!(mplace.mplace.align <= align, "dynamic alignment less strict than static one?"); + assert!(mplace.align <= align, "dynamic alignment less strict than static one?"); let align = M::enforce_alignment(self).then_some(align); self.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?; Ok(()) } - /// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is - /// always possible without allocating, so it can take `&self`. Also return the field's layout. - /// This supports both struct and array fields. - /// - /// This also works for arrays, but then the `usize` index type is restricting. - /// For indexing into arrays, use `mplace_index`. - #[inline(always)] - pub fn mplace_field( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - field: usize, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let offset = base.layout.fields.offset(field); - let field_layout = base.layout.field(self, field); - - // Offset may need adjustment for unsized fields. - let (meta, offset) = if field_layout.is_unsized() { - // Re-use parent metadata to determine dynamic field layout. - // With custom DSTS, this *will* execute user-defined code, but the same - // happens at run-time so that's okay. - match self.size_and_align_of(&base.meta, &field_layout)? { - Some((_, align)) => (base.meta, offset.align_to(align)), - None => { - // For unsized types with an extern type tail we perform no adjustments. - // NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend. - assert!(matches!(base.meta, MemPlaceMeta::None)); - (base.meta, offset) - } - } - } else { - // base.meta could be present; we might be accessing a sized field of an unsized - // struct. - (MemPlaceMeta::None, offset) - }; - - // We do not look at `base.layout.align` nor `field_layout.align`, unlike - // codegen -- mostly to see if we can get away with that - base.offset(offset, meta, field_layout, self) - } - - /// Index into an array. - #[inline(always)] - pub fn mplace_index( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - index: u64, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // Not using the layout method because we want to compute on u64 - match base.layout.fields { - FieldsShape::Array { stride, .. } => { - let len = base.len(self)?; - if index >= len { - // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len, index }); - } - let offset = stride * index; // `Size` multiplication - // All fields have the same layout. - let field_layout = base.layout.field(self, 0); - - assert!(!field_layout.is_unsized()); - base.offset(offset, MemPlaceMeta::None, field_layout, self) - } - _ => span_bug!( - self.cur_span(), - "`mplace_index` called on non-array type {:?}", - base.layout.ty - ), - } - } - - // Iterates over all fields of an array. Much more efficient than doing the - // same by repeatedly calling `mplace_array`. - pub(super) fn mplace_array_fields<'a>( - &self, - base: &'a MPlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a> - { - let len = base.len(self)?; // also asserts that we have a type where this makes sense - let FieldsShape::Array { stride, .. } = base.layout.fields else { - span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"); - }; - let layout = base.layout.field(self, 0); - let dl = &self.tcx.data_layout; - // `Size` multiplication - Ok((0..len).map(move |i| base.offset(stride * i, MemPlaceMeta::None, layout, dl))) - } - - fn mplace_subslice( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - from: u64, - to: u64, - from_end: bool, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let len = base.len(self)?; // also asserts that we have a type where this makes sense - let actual_to = if from_end { - if from.checked_add(to).map_or(true, |to| to > len) { - // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) }); - } - len.checked_sub(to).unwrap() - } else { - to - }; - - // Not using layout method because that works with usize, and does not work with slices - // (that have count 0 in their layout). - let from_offset = match base.layout.fields { - FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked - _ => { - span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout) - } - }; - - // Compute meta and new layout - let inner_len = actual_to.checked_sub(from).unwrap(); - let (meta, ty) = match base.layout.ty.kind() { - // It is not nice to match on the type, but that seems to be the only way to - // implement this. - ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)), - ty::Slice(..) => { - let len = Scalar::from_machine_usize(inner_len, self); - (MemPlaceMeta::Meta(len), base.layout.ty) - } - _ => { - span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty) - } - }; - let layout = self.layout_of(ty)?; - base.offset(from_offset, meta, layout, self) - } - - pub(crate) fn mplace_downcast( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - variant: VariantIdx, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - // Downcasts only change the layout. - // (In particular, no check about whether this is even the active variant -- that's by design, - // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) - assert!(!base.meta.has_meta()); - Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..*base }) - } - - /// Project into an mplace - #[instrument(skip(self), level = "debug")] - pub(super) fn mplace_projection( - &self, - base: &MPlaceTy<'tcx, M::PointerTag>, - proj_elem: mir::PlaceElem<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { - Field(field, _) => self.mplace_field(base, field.index())?, - Downcast(_, variant) => self.mplace_downcast(base, variant)?, - Deref => self.deref_operand(&base.into())?, - - Index(local) => { - let layout = self.layout_of(self.tcx.types.usize)?; - let n = self.access_local(self.frame(), local, Some(layout))?; - let n = self.read_scalar(&n)?; - let n = n.to_machine_usize(self)?; - self.mplace_index(base, n)? - } - - ConstantIndex { offset, min_length, from_end } => { - let n = base.len(self)?; - if n < min_length { - // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: min_length, index: n }); - } - - let index = if from_end { - assert!(0 < offset && offset <= min_length); - n.checked_sub(offset).unwrap() - } else { - assert!(offset < min_length); - offset - }; - - self.mplace_index(base, index)? - } - - Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?, - }) - } - /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. /// Also returns the number of elements. pub fn mplace_to_simd( &self, - base: &MPlaceTy<'tcx, M::PointerTag>, + mplace: &MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { // Basically we just transmute this place into an array following simd_size_and_type. // (Transmuting is okay since this is an in-memory place. We also double-check the size // stays the same.) - let (len, e_ty) = base.layout.ty.simd_size_and_type(*self.tcx); + let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); let array = self.tcx.mk_array(e_ty, len); let layout = self.layout_of(array)?; - assert_eq!(layout.size, base.layout.size); - Ok((MPlaceTy { layout, ..*base }, len)) - } - - /// Gets the place of a field inside the place, and also the field's type. - /// Just a convenience function, but used quite a bit. - /// This is the only projection that might have a side-effect: We cannot project - /// into the field of a local `ScalarPair`, we have to first allocate it. - #[instrument(skip(self), level = "debug")] - pub fn place_field( - &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, - field: usize, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - // FIXME: We could try to be smarter and avoid allocation for fields that span the - // entire place. - let mplace = self.force_allocation(base)?; - Ok(self.mplace_field(&mplace, field)?.into()) - } - - pub fn place_index( - &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, - index: u64, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - let mplace = self.force_allocation(base)?; - Ok(self.mplace_index(&mplace, index)?.into()) - } - - pub fn place_downcast( - &self, - base: &PlaceTy<'tcx, M::PointerTag>, - variant: VariantIdx, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - // Downcast just changes the layout - Ok(match base.place { - Place::Ptr(mplace) => { - self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into() - } - Place::Local { .. } => { - let layout = base.layout.for_variant(self, variant); - PlaceTy { layout, ..*base } - } - }) - } - - /// Projects into a place. - pub fn place_projection( - &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, - &proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>, - ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { - Field(field, _) => self.place_field(base, field.index())?, - Downcast(_, variant) => self.place_downcast(base, variant)?, - Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), - // For the other variants, we have to force an allocation. - // This matches `operand_projection`. - Subslice { .. } | ConstantIndex { .. } | Index(_) => { - let mplace = self.force_allocation(base)?; - self.mplace_projection(&mplace, proj_elem)?.into() - } - }) + assert_eq!(layout.size, mplace.layout.size); + Ok((MPlaceTy { layout, ..*mplace }, len)) } /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. /// Also returns the number of elements. pub fn place_to_simd( &mut self, - base: &PlaceTy<'tcx, M::PointerTag>, + place: &PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, u64)> { - let mplace = self.force_allocation(base)?; + let mplace = self.force_allocation(place)?; self.mplace_to_simd(&mplace) } + pub fn local_to_place( + &self, + frame: usize, + local: mir::Local, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + let layout = self.layout_of_local(&self.stack()[frame], local, None)?; + let place = Place::Local { frame, local }; + Ok(PlaceTy { place, layout, align: layout.align.abi }) + } + /// Computes a place. You should only use this if you intend to write into this /// place; for reading, a more efficient alternative is `eval_place_to_op`. #[instrument(skip(self), level = "debug")] pub fn eval_place( &mut self, - place: mir::Place<'tcx>, + mir_place: mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { - let mut place_ty = PlaceTy { - // This works even for dead/uninitialized locals; we check further when writing - place: Place::Local { frame: self.frame_idx(), local: place.local }, - layout: self.layout_of_local(self.frame(), place.local, None)?, - }; - - for elem in place.projection.iter() { - place_ty = self.place_projection(&place_ty, &elem)? + let mut place = self.local_to_place(self.frame_idx(), mir_place.local)?; + // Using `try_fold` turned out to be bad for performance, hence the loop. + for elem in mir_place.projection.iter() { + place = self.place_projection(&place, elem)? } - trace!("{:?}", self.dump_place(place_ty.place)); + trace!("{:?}", self.dump_place(place.place)); // Sanity-check the type we ended up with. - debug_assert!(mir_assign_valid_types( - *self.tcx, - self.param_env, - self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( - place.ty(&self.frame().body.local_decls, *self.tcx).ty - )?)?, - place_ty.layout, - )); - Ok(place_ty) + debug_assert!( + mir_assign_valid_types( + *self.tcx, + self.param_env, + self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( + mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty + )?)?, + place.layout, + ), + "eval_place of a MIR place with type {:?} produced an interpreter place with type {:?}", + mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, + place.layout.ty, + ); + Ok(place) } /// Write an immediate to a place @@ -719,32 +515,33 @@ where let mplace = match dest.place { Place::Local { frame, local } => { match M::access_local_mut(self, frame, local)? { - Ok(local) => { + Operand::Immediate(local) => { // Local can be updated in-place. - *local = LocalValue::Live(Operand::Immediate(src)); + *local = src; return Ok(()); } - Err(mplace) => { + Operand::Indirect(mplace) => { // The local is in memory, go on below. - mplace + *mplace } } } Place::Ptr(mplace) => mplace, // already referring to memory }; - let dest = MPlaceTy { mplace, layout: dest.layout }; // This is already in memory, write there. - self.write_immediate_to_mplace_no_validate(src, &dest) + self.write_immediate_to_mplace_no_validate(src, dest.layout, dest.align, mplace) } /// Write an immediate to memory. /// If you use this you are responsible for validating that things got copied at the - /// right type. + /// right layout. fn write_immediate_to_mplace_no_validate( &mut self, value: Immediate<M::PointerTag>, - dest: &MPlaceTy<'tcx, M::PointerTag>, + layout: TyAndLayout<'tcx>, + align: Align, + dest: MemPlace<M::PointerTag>, ) -> InterpResult<'tcx> { // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here @@ -752,31 +549,30 @@ where // wrong type. let tcx = *self.tcx; - let Some(mut alloc) = self.get_place_alloc_mut(dest)? else { + let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout, align })? else { // zero-sized access return Ok(()); }; match value { Immediate::Scalar(scalar) => { - let Abi::Scalar(s) = dest.layout.abi else { span_bug!( + let Abi::Scalar(s) = layout.abi else { span_bug!( self.cur_span(), - "write_immediate_to_mplace: invalid Scalar layout: {:#?}", - dest.layout + "write_immediate_to_mplace: invalid Scalar layout: {layout:#?}", ) }; let size = s.size(&tcx); - //FIXME(#96185): assert_eq!(dest.layout.size, size, "abi::Scalar size does not match layout size"); + assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); alloc.write_scalar(alloc_range(Size::ZERO, size), scalar) } Immediate::ScalarPair(a_val, b_val) => { // We checked `ptr_align` above, so all fields will have the alignment they need. // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. - let Abi::ScalarPair(a, b) = dest.layout.abi else { span_bug!( + let Abi::ScalarPair(a, b) = layout.abi else { span_bug!( self.cur_span(), "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", - dest.layout + layout ) }; let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); @@ -790,33 +586,22 @@ where alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; alloc.write_scalar(alloc_range(b_offset, b_size), b_val) } + Immediate::Uninit => alloc.write_uninit(), } } pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { - let mplace = match dest.place { - Place::Ptr(mplace) => MPlaceTy { mplace, layout: dest.layout }, - Place::Local { frame, local } => { + let mplace = match dest.try_as_mplace() { + Ok(mplace) => mplace, + Err((frame, local)) => { match M::access_local_mut(self, frame, local)? { - Ok(local) => match dest.layout.abi { - Abi::Scalar(_) => { - *local = LocalValue::Live(Operand::Immediate(Immediate::Scalar( - ScalarMaybeUninit::Uninit, - ))); - return Ok(()); - } - Abi::ScalarPair(..) => { - *local = LocalValue::Live(Operand::Immediate(Immediate::ScalarPair( - ScalarMaybeUninit::Uninit, - ScalarMaybeUninit::Uninit, - ))); - return Ok(()); - } - _ => self.force_allocation(dest)?, - }, - Err(mplace) => { + Operand::Immediate(local) => { + *local = Immediate::Uninit; + return Ok(()); + } + Operand::Indirect(mplace) => { // The local is in memory, go on below. - MPlaceTy { mplace, layout: dest.layout } + MPlaceTy { mplace: *mplace, layout: dest.layout, align: dest.align } } } } @@ -829,16 +614,17 @@ where Ok(()) } - /// Copies the data from an operand to a place. This does not support transmuting! - /// Use `copy_op_transmute` if the layouts could disagree. + /// Copies the data from an operand to a place. + /// `allow_transmute` indicates whether the layouts may disagree. #[inline(always)] #[instrument(skip(self), level = "debug")] pub fn copy_op( &mut self, src: &OpTy<'tcx, M::PointerTag>, dest: &PlaceTy<'tcx, M::PointerTag>, + allow_transmute: bool, ) -> InterpResult<'tcx> { - self.copy_op_no_validate(src, dest)?; + self.copy_op_no_validate(src, dest, allow_transmute)?; if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! @@ -848,8 +634,8 @@ where Ok(()) } - /// Copies the data from an operand to a place. This does not support transmuting! - /// Use `copy_op_transmute` if the layouts could disagree. + /// Copies the data from an operand to a place. + /// `allow_transmute` indicates whether the layouts may disagree. /// Also, if you use this you are responsible for validating that things get copied at the /// right type. #[instrument(skip(self), level = "debug")] @@ -857,10 +643,13 @@ where &mut self, src: &OpTy<'tcx, M::PointerTag>, dest: &PlaceTy<'tcx, M::PointerTag>, + allow_transmute: bool, ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { + let layout_compat = + mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout); + if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", @@ -869,100 +658,68 @@ where ); } - // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. + // Let us see if the layout is simple so we take a shortcut, + // avoid force_allocation. let src = match self.read_immediate_raw(src, /*force*/ false)? { Ok(src_val) => { assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); + assert!( + !dest.layout.is_unsized(), + "the src is sized, so the dest must also be sized" + ); + assert_eq!(src.layout.size, dest.layout.size); // Yay, we got a value that we can write directly. - return self.write_immediate_no_validate(*src_val, dest); + return if layout_compat { + self.write_immediate_no_validate(*src_val, dest) + } else { + // This is tricky. The problematic case is `ScalarPair`: the `src_val` was + // loaded using the offsets defined by `src.layout`. When we put this back into + // the destination, we have to use the same offsets! So (a) we make sure we + // write back to memory, and (b) we use `dest` *with the source layout*. + let dest_mem = self.force_allocation(dest)?; + self.write_immediate_to_mplace_no_validate( + *src_val, + src.layout, + dest_mem.align, + *dest_mem, + ) + }; } Err(mplace) => mplace, }; // Slow path, this does not fit into an immediate. Just memcpy. trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); - // This interprets `src.meta` with the `dest` local's layout, if an unsized local - // is being initialized! - let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?; - let size = size.unwrap_or_else(|| { - assert!( - !dest.layout.is_unsized(), - "Cannot copy into already initialized unsized place" - ); - dest.layout.size - }); - assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); - - self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ false) - } - - /// Copies the data from an operand to a place. The layouts may disagree, but they must - /// have the same size. - pub fn copy_op_transmute( - &mut self, - src: &OpTy<'tcx, M::PointerTag>, - dest: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) { - // Fast path: Just use normal `copy_op` - return self.copy_op(src, dest); - } - // We still require the sizes to match. - if src.layout.size != dest.layout.size { - span_bug!( - self.cur_span(), - "size-changing transmute, should have been caught by transmute checking: {:#?}\ndest: {:#?}", - src, - dest - ); - } - // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want - // to avoid that here. - assert!( - !src.layout.is_unsized() && !dest.layout.is_unsized(), - "Cannot transmute unsized data" - ); - - // The hard case is `ScalarPair`. `src` is already read from memory in this case, - // using `src.layout` to figure out which bytes to use for the 1st and 2nd field. - // We have to write them to `dest` at the offsets they were *read at*, which is - // not necessarily the same as the offsets in `dest.layout`! - // Hence we do the copy with the source layout on both sides. We also make sure to write - // into memory, because if `dest` is a local we would not even have a way to write - // at the `src` offsets; the fact that we came from a different layout would - // just be lost. - let dest = self.force_allocation(dest)?; - self.copy_op_no_validate( - src, - &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }), - )?; - - if M::enforce_validity(self) { - // Data got changed, better make sure it matches the type! - self.validate_operand(&dest.into())?; + let dest = self.force_allocation(&dest)?; + let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else { + span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values") + }; + if cfg!(debug_assertions) { + let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0; + assert_eq!(src_size, dest_size, "Cannot copy differently-sized data"); + } else { + // As a cheap approximation, we compare the fixed parts of the size. + assert_eq!(src.layout.size, dest.layout.size); } - Ok(()) + self.mem_copy( + src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ false, + ) } /// Ensures that a place is in memory, and returns where it is. /// If the place currently refers to a local that doesn't yet have a matching allocation, /// create such an allocation. /// This is essentially `force_to_memplace`. - /// - /// This supports unsized types and returns the computed size to avoid some - /// redundant computation when copying; use `force_allocation` for a simpler, sized-only - /// version. #[instrument(skip(self), level = "debug")] - pub fn force_allocation_maybe_sized( + pub fn force_allocation( &mut self, place: &PlaceTy<'tcx, M::PointerTag>, - meta: MemPlaceMeta<M::PointerTag>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> { - let (mplace, size) = match place.place { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let mplace = match place.place { Place::Local { frame, local } => { match M::access_local_mut(self, frame, local)? { - Ok(&mut local_val) => { + &mut Operand::Immediate(local_val) => { // We need to make an allocation. // We need the layout of the local. We can NOT use the layout we got, @@ -970,40 +727,34 @@ where // that has different alignment than the outer field. let local_layout = self.layout_of_local(&self.stack()[frame], local, None)?; - // We also need to support unsized types, and hence cannot use `allocate`. - let (size, align) = self - .size_and_align_of(&meta, &local_layout)? - .expect("Cannot allocate for non-dyn-sized type"); - let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?; - let mplace = MemPlace { ptr: ptr.into(), align, meta }; - if let LocalValue::Live(Operand::Immediate(value)) = local_val { - // Preserve old value. + if local_layout.is_unsized() { + throw_unsup_format!("unsized locals are not supported"); + } + let mplace = *self.allocate(local_layout, MemoryKind::Stack)?; + if !matches!(local_val, Immediate::Uninit) { + // Preserve old value. (As an optimization, we can skip this if it was uninit.) // We don't have to validate as we can assume the local // was already valid for its type. - let mplace = MPlaceTy { mplace, layout: local_layout }; - self.write_immediate_to_mplace_no_validate(value, &mplace)?; + self.write_immediate_to_mplace_no_validate( + local_val, + local_layout, + local_layout.align.abi, + mplace, + )?; } // Now we can call `access_mut` again, asserting it goes well, // and actually overwrite things. - *M::access_local_mut(self, frame, local).unwrap().unwrap() = - LocalValue::Live(Operand::Indirect(mplace)); - (mplace, Some(size)) + *M::access_local_mut(self, frame, local).unwrap() = + Operand::Indirect(mplace); + mplace } - Err(mplace) => (mplace, None), // this already was an indirect local + &mut Operand::Indirect(mplace) => mplace, // this already was an indirect local } } - Place::Ptr(mplace) => (mplace, None), + Place::Ptr(mplace) => mplace, }; // Return with the original layout, so that the caller can go on - Ok((MPlaceTy { mplace, layout: place.layout }, size)) - } - - #[inline(always)] - pub fn force_allocation( - &mut self, - place: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0) + Ok(MPlaceTy { mplace, layout: place.layout, align: place.align }) } pub fn allocate( @@ -1011,6 +762,7 @@ where layout: TyAndLayout<'tcx>, kind: MemoryKind<M::MemoryKind>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + assert!(!layout.is_unsized()); let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?; Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) } @@ -1024,15 +776,14 @@ where ) -> MPlaceTy<'tcx, M::PointerTag> { let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl); let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); - let mplace = - MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) }; + let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; let ty = self.tcx.mk_ref( self.tcx.lifetimes.re_static, ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, ); let layout = self.layout_of(ty).unwrap(); - MPlaceTy { mplace, layout } + MPlaceTy { mplace, layout, align: layout.align.abi } } /// Writes the discriminant of the given variant. @@ -1062,10 +813,10 @@ where } match dest.layout.variants { - Variants::Single { index } => { + abi::Variants::Single { index } => { assert_eq!(index, variant_index); } - Variants::Multiple { + abi::Variants::Multiple { tag_encoding: TagEncoding::Direct, tag: tag_layout, tag_field, @@ -1086,7 +837,7 @@ where let tag_dest = self.place_field(dest, tag_field)?; self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?; } - Variants::Multiple { + abi::Variants::Multiple { tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, tag: tag_layout, @@ -1152,7 +903,11 @@ where assert_eq!(align, layout.align.abi); } - let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout }; + let mplace = MPlaceTy { + mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, + layout, + align: layout.align.abi, + }; Ok((instance, mplace)) } } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs new file mode 100644 index 0000000000000..704dc6db06071 --- /dev/null +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -0,0 +1,401 @@ +//! This file implements "place projections"; basically a symmetric API for 3 types: MPlaceTy, OpTy, PlaceTy. +//! +//! OpTy and PlaceTy genrally work by "let's see if we are actually an MPlaceTy, and do something custom if not". +//! For PlaceTy, the custom thing is basically always to call `force_allocation` and then use the MPlaceTy logic anyway. +//! For OpTy, the custom thing on field pojections has to be pretty clever (since `Operand::Immediate` can have fields), +//! but for array/slice operations it only has to worry about `Operand::Uninit`. That makes the value part trivial, +//! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually +//! implement the logic on OpTy, and MPlaceTy calls that. + +use std::hash::Hash; + +use rustc_middle::mir; +use rustc_middle::ty; +use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::{self, Abi, VariantIdx}; + +use super::{ + ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, PlaceTy, + Provenance, Scalar, +}; + +// FIXME: Working around https://github.com/rust-lang/rust/issues/54385 +impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> +where + Tag: Provenance + Eq + Hash + 'static, + M: Machine<'mir, 'tcx, PointerTag = Tag>, +{ + //# Field access + + /// Offset a pointer to project to a field of a struct/union. Unlike `place_field`, this is + /// always possible without allocating, so it can take `&self`. Also return the field's layout. + /// This supports both struct and array fields. + /// + /// This also works for arrays, but then the `usize` index type is restricting. + /// For indexing into arrays, use `mplace_index`. + pub fn mplace_field( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + field: usize, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let offset = base.layout.fields.offset(field); + let field_layout = base.layout.field(self, field); + + // Offset may need adjustment for unsized fields. + let (meta, offset) = if field_layout.is_unsized() { + // Re-use parent metadata to determine dynamic field layout. + // With custom DSTS, this *will* execute user-defined code, but the same + // happens at run-time so that's okay. + match self.size_and_align_of(&base.meta, &field_layout)? { + Some((_, align)) => (base.meta, offset.align_to(align)), + None => { + // For unsized types with an extern type tail we perform no adjustments. + // NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend. + assert!(matches!(base.meta, MemPlaceMeta::None)); + (base.meta, offset) + } + } + } else { + // base.meta could be present; we might be accessing a sized field of an unsized + // struct. + (MemPlaceMeta::None, offset) + }; + + // We do not look at `base.layout.align` nor `field_layout.align`, unlike + // codegen -- mostly to see if we can get away with that + base.offset_with_meta(offset, meta, field_layout, self) + } + + /// Gets the place of a field inside the place, and also the field's type. + /// Just a convenience function, but used quite a bit. + /// This is the only projection that might have a side-effect: We cannot project + /// into the field of a local `ScalarPair`, we have to first allocate it. + pub fn place_field( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + field: usize, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + // FIXME: We could try to be smarter and avoid allocation for fields that span the + // entire place. + let base = self.force_allocation(base)?; + Ok(self.mplace_field(&base, field)?.into()) + } + + pub fn operand_field( + &self, + base: &OpTy<'tcx, M::PointerTag>, + field: usize, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let base = match base.try_as_mplace() { + Ok(ref mplace) => { + // We can reuse the mplace field computation logic for indirect operands. + let field = self.mplace_field(mplace, field)?; + return Ok(field.into()); + } + Err(value) => value, + }; + + let field_layout = base.layout.field(self, field); + let offset = base.layout.fields.offset(field); + // This makes several assumptions about what layouts we will encounter; we match what + // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). + let field_val: Immediate<_> = match (*base, base.layout.abi) { + // the field contains no information, can be left uninit + _ if field_layout.is_zst() => Immediate::Uninit, + // the field covers the entire type + _ if field_layout.size == base.layout.size => { + assert!(match (base.layout.abi, field_layout.abi) { + (Abi::Scalar(..), Abi::Scalar(..)) => true, + (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true, + _ => false, + }); + assert!(offset.bytes() == 0); + *base + } + // extract fields from types with `ScalarPair` ABI + (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { + assert!(matches!(field_layout.abi, Abi::Scalar(..))); + Immediate::from(if offset.bytes() == 0 { + debug_assert_eq!(field_layout.size, a.size(self)); + a_val + } else { + debug_assert_eq!(offset, a.size(self).align_to(b.align(self).abi)); + debug_assert_eq!(field_layout.size, b.size(self)); + b_val + }) + } + _ => span_bug!( + self.cur_span(), + "invalid field access on immediate {}, layout {:#?}", + base, + base.layout + ), + }; + + Ok(ImmTy::from_immediate(field_val, field_layout).into()) + } + + //# Downcasting + + pub fn mplace_downcast( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + variant: VariantIdx, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + // Downcasts only change the layout. + // (In particular, no check about whether this is even the active variant -- that's by design, + // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.) + assert!(!base.meta.has_meta()); + let mut base = *base; + base.layout = base.layout.for_variant(self, variant); + Ok(base) + } + + pub fn place_downcast( + &self, + base: &PlaceTy<'tcx, M::PointerTag>, + variant: VariantIdx, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + // Downcast just changes the layout + let mut base = *base; + base.layout = base.layout.for_variant(self, variant); + Ok(base) + } + + pub fn operand_downcast( + &self, + base: &OpTy<'tcx, M::PointerTag>, + variant: VariantIdx, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Downcast just changes the layout + let mut base = *base; + base.layout = base.layout.for_variant(self, variant); + Ok(base) + } + + //# Slice indexing + + #[inline(always)] + pub fn operand_index( + &self, + base: &OpTy<'tcx, M::PointerTag>, + index: u64, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // Not using the layout method because we want to compute on u64 + match base.layout.fields { + abi::FieldsShape::Array { stride, count: _ } => { + // `count` is nonsense for slices, use the dynamic length instead. + let len = base.len(self)?; + if index >= len { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len, index }); + } + let offset = stride * index; // `Size` multiplication + // All fields have the same layout. + let field_layout = base.layout.field(self, 0); + base.offset(offset, field_layout, self) + } + _ => span_bug!( + self.cur_span(), + "`mplace_index` called on non-array type {:?}", + base.layout.ty + ), + } + } + + // Iterates over all fields of an array. Much more efficient than doing the + // same by repeatedly calling `operand_index`. + pub fn operand_array_fields<'a>( + &self, + base: &'a OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, OpTy<'tcx, Tag>>> + 'a> { + let len = base.len(self)?; // also asserts that we have a type where this makes sense + let abi::FieldsShape::Array { stride, .. } = base.layout.fields else { + span_bug!(self.cur_span(), "operand_array_fields: expected an array layout"); + }; + let field_layout = base.layout.field(self, 0); + let dl = &self.tcx.data_layout; + // `Size` multiplication + Ok((0..len).map(move |i| base.offset(stride * i, field_layout, dl))) + } + + /// Index into an array. + pub fn mplace_index( + &self, + base: &MPlaceTy<'tcx, M::PointerTag>, + index: u64, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + Ok(self.operand_index(&base.into(), index)?.assert_mem_place()) + } + + pub fn place_index( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + index: u64, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + // There's not a lot we can do here, since we cannot have a place to a part of a local. If + // we are accessing the only element of a 1-element array, it's still the entire local... + // that doesn't seem worth it. + let base = self.force_allocation(base)?; + Ok(self.mplace_index(&base, index)?.into()) + } + + //# ConstantIndex support + + fn operand_constant_index( + &self, + base: &OpTy<'tcx, M::PointerTag>, + offset: u64, + min_length: u64, + from_end: bool, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let n = base.len(self)?; + if n < min_length { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len: min_length, index: n }); + } + + let index = if from_end { + assert!(0 < offset && offset <= min_length); + n.checked_sub(offset).unwrap() + } else { + assert!(offset < min_length); + offset + }; + + self.operand_index(base, index) + } + + fn place_constant_index( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + offset: u64, + min_length: u64, + from_end: bool, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + let base = self.force_allocation(base)?; + Ok(self + .operand_constant_index(&base.into(), offset, min_length, from_end)? + .assert_mem_place() + .into()) + } + + //# Subslicing + + fn operand_subslice( + &self, + base: &OpTy<'tcx, M::PointerTag>, + from: u64, + to: u64, + from_end: bool, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let len = base.len(self)?; // also asserts that we have a type where this makes sense + let actual_to = if from_end { + if from.checked_add(to).map_or(true, |to| to > len) { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) }); + } + len.checked_sub(to).unwrap() + } else { + to + }; + + // Not using layout method because that works with usize, and does not work with slices + // (that have count 0 in their layout). + let from_offset = match base.layout.fields { + abi::FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked + _ => { + span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout) + } + }; + + // Compute meta and new layout + let inner_len = actual_to.checked_sub(from).unwrap(); + let (meta, ty) = match base.layout.ty.kind() { + // It is not nice to match on the type, but that seems to be the only way to + // implement this. + ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)), + ty::Slice(..) => { + let len = Scalar::from_machine_usize(inner_len, self); + (MemPlaceMeta::Meta(len), base.layout.ty) + } + _ => { + span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty) + } + }; + let layout = self.layout_of(ty)?; + base.offset_with_meta(from_offset, meta, layout, self) + } + + pub fn place_subslice( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + from: u64, + to: u64, + from_end: bool, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + let base = self.force_allocation(base)?; + Ok(self.operand_subslice(&base.into(), from, to, from_end)?.assert_mem_place().into()) + } + + //# Applying a general projection + + /// Projects into a place. + #[instrument(skip(self), level = "trace")] + pub fn place_projection( + &mut self, + base: &PlaceTy<'tcx, M::PointerTag>, + proj_elem: mir::PlaceElem<'tcx>, + ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { + use rustc_middle::mir::ProjectionElem::*; + Ok(match proj_elem { + OpaqueCast(ty) => { + let mut place = *base; + place.layout = self.layout_of(ty)?; + place + } + Field(field, _) => self.place_field(base, field.index())?, + Downcast(_, variant) => self.place_downcast(base, variant)?, + Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), + Index(local) => { + let layout = self.layout_of(self.tcx.types.usize)?; + let n = self.local_to_op(self.frame(), local, Some(layout))?; + let n = self.read_scalar(&n)?.to_machine_usize(self)?; + self.place_index(base, n)? + } + ConstantIndex { offset, min_length, from_end } => { + self.place_constant_index(base, offset, min_length, from_end)? + } + Subslice { from, to, from_end } => self.place_subslice(base, from, to, from_end)?, + }) + } + + #[instrument(skip(self), level = "trace")] + pub fn operand_projection( + &self, + base: &OpTy<'tcx, M::PointerTag>, + proj_elem: mir::PlaceElem<'tcx>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + use rustc_middle::mir::ProjectionElem::*; + Ok(match proj_elem { + OpaqueCast(ty) => { + let mut op = *base; + op.layout = self.layout_of(ty)?; + op + } + Field(field, _) => self.operand_field(base, field.index())?, + Downcast(_, variant) => self.operand_downcast(base, variant)?, + Deref => self.deref_operand(base)?.into(), + Index(local) => { + let layout = self.layout_of(self.tcx.types.usize)?; + let n = self.local_to_op(self.frame(), local, Some(layout))?; + let n = self.read_scalar(&n)?.to_machine_usize(self)?; + self.operand_index(base, n)? + } + ConstantIndex { offset, min_length, from_end } => { + self.operand_constant_index(base, offset, min_length, from_end)? + } + Subslice { from, to, from_end } => self.operand_subslice(base, from, to, from_end)?, + }) + } +} diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 98f69456e49aa..fea158a9fe450 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -169,7 +169,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Use(ref operand) => { // Avoid recomputing the layout let op = self.eval_operand(operand, Some(dest.layout))?; - self.copy_op(&op, &dest)?; + self.copy_op(&op, &dest, /*allow_transmute*/ false)?; + } + + CopyForDeref(ref place) => { + let op = self.eval_place_to_op(*place, Some(dest.layout))?; + self.copy_op(&op, &dest, /* allow_transmute*/ false)?; } BinaryOp(bin_op, box (ref left, ref right)) => { @@ -185,7 +190,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let left = self.read_immediate(&self.eval_operand(left, None)?)?; let layout = binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(&self.eval_operand(right, layout)?)?; - self.binop_with_overflow(bin_op, &left, &right, &dest)?; + self.binop_with_overflow( + bin_op, /*force_overflow_checks*/ false, &left, &right, &dest, + )?; } UnaryOp(un_op, ref operand) => { @@ -202,7 +209,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (field_index, operand) in operands.iter().enumerate() { let op = self.eval_operand(operand, None)?; let field_dest = self.place_field(&dest, field_index)?; - self.copy_op(&op, &field_dest)?; + self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; } } @@ -218,7 +225,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { // Write the src to the first element. let first = self.mplace_field(&dest, 0)?; - self.copy_op(&src, &first.into())?; + self.copy_op(&src, &first.into(), /*allow_transmute*/ false)?; // This is performance-sensitive code for big static/const arrays! So we // avoid writing each operand individually and instead just make many copies diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 57d06b48ca4da..20122f8131c33 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -12,8 +12,8 @@ use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMo use rustc_target::spec::abi::Abi; use super::{ - FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Scalar, - StackPopCleanup, StackPopUnwind, + FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand, + PlaceTy, Scalar, StackPopCleanup, StackPopUnwind, }; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -185,11 +185,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // No question return true; } + if caller_abi.layout.is_unsized() || callee_abi.layout.is_unsized() { + // No, no, no. We require the types to *exactly* match for unsized arguments. If + // these are somehow unsized "in a different way" (say, `dyn Trait` vs `[i32]`), + // then who knows what happens. + return false; + } if caller_abi.layout.size != callee_abi.layout.size || caller_abi.layout.align.abi != callee_abi.layout.align.abi { // This cannot go well... - // FIXME: What about unsized types? return false; } // The rest *should* be okay, but we are extra conservative. @@ -287,11 +292,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_arg.layout.ty ) } + // Special handling for unsized parameters. + if caller_arg.layout.is_unsized() { + // `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way. + assert_eq!(caller_arg.layout.ty, callee_arg.layout.ty); + // We have to properly pre-allocate the memory for the callee. + // So let's tear down some wrappers. + // This all has to be in memory, there are no immediate unsized values. + let src = caller_arg.assert_mem_place(); + // The destination cannot be one of these "spread args". + let (dest_frame, dest_local) = callee_arg.assert_local(); + // We are just initializing things, so there can't be anything here yet. + assert!(matches!( + *self.local_to_op(&self.stack()[dest_frame], dest_local, None)?, + Operand::Immediate(Immediate::Uninit) + )); + // Allocate enough memory to hold `src`. + let Some((size, align)) = self.size_and_align_of_mplace(&src)? else { + span_bug!(self.cur_span(), "unsized fn arg with `extern` type tail should not be allowed") + }; + let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?; + let dest_place = + MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), callee_arg.layout, src.meta); + // Update the local to be that new place. + *M::access_local_mut(self, dest_frame, dest_local)? = Operand::Indirect(*dest_place); + } // We allow some transmutes here. // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This // is true for all `copy_op`, but there are a lot of special cases for argument passing // specifically.) - self.copy_op_transmute(&caller_arg, callee_arg) + self.copy_op(&caller_arg, callee_arg, /*allow_transmute*/ true) } /// Call this function -- pushing the stack frame and initializing the arguments. @@ -499,7 +529,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let receiver_place = loop { match receiver.layout.ty.kind() { ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?, - ty::Dynamic(..) => break receiver.assert_mem_place(), + ty::Dynamic(..) => break receiver.assert_mem_place(), // no immediate unsized values _ => { // Not there yet, search for the only non-ZST field. let mut non_zst_field = None; @@ -587,16 +617,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { place.to_ref(self), self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?, ); - - let ty = self.tcx.mk_unit(); // return type is () - let dest = MPlaceTy::dangling(self.layout_of(ty)?); + let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?); self.eval_fn_call( FnVal::Instance(instance), (Abi::Rust, fn_abi), &[arg.into()], false, - &dest.into(), + &ret.into(), Some(target), match unwind { Some(cleanup) => StackPopUnwind::Cleanup(cleanup), diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 9c48f3e833760..22c23df7b1ab3 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic}; +use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic}; use rustc_middle::ty::{ self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE, @@ -102,18 +102,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )? .expect("cannot be a ZST"); let size = vtable - .read_integer( + .read_integer(alloc_range( pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(), pointer_size, - )? + ))? .check_init()?; let size = size.to_machine_usize(self)?; let size = Size::from_bytes(size); let align = vtable - .read_integer( + .read_integer(alloc_range( pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(), pointer_size, - )? + ))? .check_init()?; let align = align.to_machine_usize(self)?; let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index b9866995e9f95..2bc521d5bbe0b 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,5 +1,5 @@ use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use std::convert::TryInto; use std::ops::ControlFlow; @@ -10,7 +10,7 @@ use std::ops::ControlFlow; /// case these parameters are unused. pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { debug!("ensure_monomorphic_enough: ty={:?}", ty); if !ty.needs_subst() { @@ -44,22 +44,10 @@ where let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. - match (is_used, subst.needs_subst()) { - // Just in case there are closures or generators within this subst, - // recurse. - (true, true) => return subst.visit_with(self), - // Confirm that polymorphization replaced the parameter with - // `ty::Param`/`ty::ConstKind::Param`. - (false, true) if cfg!(debug_assertions) => match subst.unpack() { - ty::subst::GenericArgKind::Type(ty) => { - assert!(matches!(ty.kind(), ty::Param(_))) - } - ty::subst::GenericArgKind::Const(ct) => { - assert!(matches!(ct.kind(), ty::ConstKind::Param(_))) - } - ty::subst::GenericArgKind::Lifetime(..) => (), - }, - _ => {} + // Just in case there are closures or generators within this subst, + // recurse. + if is_used && subst.needs_subst() { + return subst.visit_with(self); } } ControlFlow::CONTINUE diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 630281bb09254..2e5492ecf5601 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -244,7 +244,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // for a generator). let var_hir_id = captured_place.get_root_variable(); let node = self.ecx.tcx.hir().get(var_hir_id); - if let hir::Node::Binding(pat) = node { + if let hir::Node::Pat(pat) = node { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { name = Some(ident.name); } @@ -427,7 +427,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' err_ub!(DanglingIntPointer(0, _)) => { "a null {kind}" }, err_ub!(DanglingIntPointer(i, _)) => - { "a dangling {kind} (address 0x{i:x} is unallocated)" }, + { "a dangling {kind} (address {i:#x} is unallocated)" }, err_ub!(PointerOutOfBounds { .. }) => { "a dangling {kind} (going beyond the bounds of its allocation)" }, // This cannot happen during const-eval (because interning already detects @@ -593,10 +593,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' self.check_safe_pointer(value, "reference")?; Ok(true) } - ty::Adt(def, ..) if def.is_box() => { - self.check_safe_pointer(value, "box")?; - Ok(true) - } ty::FnPtr(_sig) => { let value = try_validation!( self.ecx.read_scalar(value).and_then(|v| v.check_init()), @@ -807,6 +803,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Ok(()) } + #[inline] + fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + self.check_safe_pointer(op, "box")?; + Ok(()) + } + #[inline] fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); @@ -815,13 +817,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> if self.try_visit_primitive(op)? { return Ok(()); } - // Sanity check: `builtin_deref` does not know any pointers that are not primitive. - assert!(op.layout.ty.builtin_deref(true).is_none()); // Special check preventing `UnsafeCell` in the inner part of constants if let Some(def) = op.layout.ty.ty_adt_def() { if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) - && Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() + && def.is_unsafe_cell() { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); } @@ -847,15 +847,20 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ); } Abi::Scalar(scalar_layout) => { + // We use a 'forced' read because we always need a `Immediate` here + // and treating "partially uninit" as "fully uninit" is fine for us. let scalar = self.read_immediate_forced(op)?.to_scalar_or_uninit(); self.visit_scalar(scalar, scalar_layout)?; } Abi::ScalarPair(a_layout, b_layout) => { - // We would validate these things as we descend into the fields, + // There is no `rustc_layout_scalar_valid_range_start` for pairs, so + // we would validate these things as we descend into the fields, // but that can miss bugs in layout computation. Layout computation // is subtle due to enums having ScalarPair layout, where one field // is the discriminant. if cfg!(debug_assertions) { + // We use a 'forced' read because we always need a `Immediate` here + // and treating "partially uninit" as "fully uninit" is fine for us. let (a, b) = self.read_immediate_forced(op)?.to_scalar_or_uninit_pair(); self.visit_scalar(a, a_layout)?; self.visit_scalar(b, b_layout)?; @@ -863,7 +868,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } Abi::Vector { .. } => { // No checks here, we assume layout computation gets this right. - // (This is harder to check since Miri does not represent these as `Immediate`.) + // (This is harder to check since Miri does not represent these as `Immediate`. We + // also cannot use field projections since this might be a newtype around a vector.) } Abi::Aggregate { .. } => { // Nothing to do. @@ -880,7 +886,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ) -> InterpResult<'tcx> { match op.layout.ty.kind() { ty::Str => { - let mplace = op.assert_mem_place(); // strings are never immediate + let mplace = op.assert_mem_place(); // strings are unsized and hence never immediate let len = mplace.len(self.ecx)?; try_validation!( self.ecx.read_bytes_ptr(mplace.ptr, Size::from_bytes(len)), @@ -900,14 +906,27 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> { // Optimized handling for arrays of integer/float type. - // Arrays cannot be immediate, slices are never immediate. - let mplace = op.assert_mem_place(); // This is the length of the array/slice. - let len = mplace.len(self.ecx)?; + let len = op.len(self.ecx)?; // This is the element type size. let layout = self.ecx.layout_of(*tys)?; // This is the size in bytes of the whole array. (This checks for overflow.) let size = layout.size * len; + // If the size is 0, there is nothing to check. + // (`size` can only be 0 of `len` is 0, and empty arrays are always valid.) + if size == Size::ZERO { + return Ok(()); + } + // Now that we definitely have a non-ZST array, we know it lives in memory. + let mplace = match op.try_as_mplace() { + Ok(mplace) => mplace, + Err(imm) => match *imm { + Immediate::Uninit => + throw_validation_failure!(self.path, { "uninitialized bytes" }), + Immediate::Scalar(..) | Immediate::ScalarPair(..) => + bug!("arrays/slices can never have Scalar/ScalarPair layout"), + } + }; // Optimization: we just check the entire range at once. // NOTE: Keep this in sync with the handling of integer and float @@ -919,10 +938,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // to reject those pointers, we just do not have the machinery to // talk about parts of a pointer. // We also accept uninit, for consistency with the slow path. - let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, mplace.align)? else { - // Size 0, nothing more to check. - return Ok(()); - }; + let alloc = self.ecx.get_ptr_alloc(mplace.ptr, size, mplace.align)?.expect("we already excluded size 0"); match alloc.check_bytes( alloc_range(Size::ZERO, size), @@ -941,7 +957,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // element that byte belongs to so we can // provide an index. let i = usize::try_from( - access.uninit_offset.bytes() / layout.size.bytes(), + access.uninit.start.bytes() / layout.size.bytes(), ) .unwrap(); self.path.push(PathElem::ArrayElem(i)); diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 679d30227f136..f6a0c19d25953 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -8,21 +8,33 @@ use rustc_target::abi::{FieldsShape, VariantIdx, Variants}; use std::num::NonZeroUsize; -use super::{InterpCx, MPlaceTy, Machine, OpTy}; +use super::{InterpCx, MPlaceTy, Machine, OpTy, PlaceTy}; -// A thing that we can project into, and that has a layout. -// This wouldn't have to depend on `Machine` but with the current type inference, -// that's just more convenient to work with (avoids repeating all the `Machine` bounds). +/// A thing that we can project into, and that has a layout. +/// This wouldn't have to depend on `Machine` but with the current type inference, +/// that's just more convenient to work with (avoids repeating all the `Machine` bounds). pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { /// Gets this value's layout. fn layout(&self) -> TyAndLayout<'tcx>; - /// Makes this into an `OpTy`. - fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>) - -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + /// Makes this into an `OpTy`, in a cheap way that is good for reading. + fn to_op_for_read( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. + fn to_op_for_proj( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + self.to_op_for_read(ecx) + } - /// Creates this from an `MPlaceTy`. - fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self; + /// Creates this from an `OpTy`. + /// + /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; /// Projects to the given enum variant. fn project_downcast( @@ -39,8 +51,50 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { ) -> InterpResult<'tcx, Self>; } -// Operands and memory-places are both values. -// Places in general are not due to `place_field` having to do `force_allocation`. +/// A thing that we can project into given *mutable* access to `ecx`, and that has a layout. +/// This wouldn't have to depend on `Machine` but with the current type inference, +/// that's just more convenient to work with (avoids repeating all the `Machine` bounds). +pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy { + /// Gets this value's layout. + fn layout(&self) -> TyAndLayout<'tcx>; + + /// Makes this into an `OpTy`, in a cheap way that is good for reading. + fn to_op_for_read( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Makes this into an `OpTy`, in a potentially more expensive way that is good for projections. + fn to_op_for_proj( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>; + + /// Creates this from an `OpTy`. + /// + /// If `to_op_for_proj` only ever produces `Indirect` operands, then this one is definitely `Indirect`. + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self; + + /// Projects to the given enum variant. + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self>; + + /// Projects to the n-th field. + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self>; +} + +// We cannot have a general impl which shows that Value implies ValueMut. (When we do, it says we +// cannot `impl ValueMut for PlaceTy` because some downstream crate could `impl Value for PlaceTy`.) +// So we have some copy-paste here. (We could have a macro but since we only have 2 types with this +// double-impl, that would barely make the code shorter, if at all.) + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tcx, M::PointerTag> { #[inline(always)] fn layout(&self) -> TyAndLayout<'tcx> { @@ -48,7 +102,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } #[inline(always)] - fn to_op( + fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { @@ -56,8 +110,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } #[inline(always)] - fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { - mplace.into() + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + *op } #[inline(always)] @@ -79,6 +133,54 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc } } +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> + for OpTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op_for_read( + &self, + _ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(*self) + } + + #[inline(always)] + fn to_op_for_proj( + &self, + _ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(*self) + } + + #[inline(always)] + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + *op + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.operand_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.operand_field(self, field) + } +} + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for MPlaceTy<'tcx, M::PointerTag> { @@ -88,16 +190,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } #[inline(always)] - fn to_op( + fn to_op_for_read( &self, _ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - Ok((*self).into()) + Ok(self.into()) } #[inline(always)] - fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self { - mplace + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + // assert is justified because our `to_op_for_read` only ever produces `Indirect` operands. + op.assert_mem_place() } #[inline(always)] @@ -119,11 +222,111 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> } } +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> + for MPlaceTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op_for_read( + &self, + _ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(self.into()) + } + + #[inline(always)] + fn to_op_for_proj( + &self, + _ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + Ok(self.into()) + } + + #[inline(always)] + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + // assert is justified because our `to_op_for_proj` only ever produces `Indirect` operands. + op.assert_mem_place() + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.mplace_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.mplace_field(self, field) + } +} + +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M> + for PlaceTy<'tcx, M::PointerTag> +{ + #[inline(always)] + fn layout(&self) -> TyAndLayout<'tcx> { + self.layout + } + + #[inline(always)] + fn to_op_for_read( + &self, + ecx: &InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // We `force_allocation` here so that `from_op` below can work. + ecx.place_to_op(self) + } + + #[inline(always)] + fn to_op_for_proj( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + // We `force_allocation` here so that `from_op` below can work. + Ok(ecx.force_allocation(self)?.into()) + } + + #[inline(always)] + fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self { + // assert is justified because our `to_op` only ever produces `Indirect` operands. + op.assert_mem_place().into() + } + + #[inline(always)] + fn project_downcast( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + variant: VariantIdx, + ) -> InterpResult<'tcx, Self> { + ecx.place_downcast(self, variant) + } + + #[inline(always)] + fn project_field( + &self, + ecx: &mut InterpCx<'mir, 'tcx, M>, + field: usize, + ) -> InterpResult<'tcx, Self> { + ecx.place_field(self, field) + } +} + macro_rules! make_value_visitor { - ($visitor_trait_name:ident, $($mutability:ident)?) => { + ($visitor_trait:ident, $value_trait:ident, $($mutability:ident)?) => { // How to traverse a value and what to do when we are at the leaves. - pub trait $visitor_trait_name<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { - type V: Value<'mir, 'tcx, M>; + pub trait $visitor_trait<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { + type V: $value_trait<'mir, 'tcx, M>; /// The visitor must have an `InterpCx` in it. fn ecx(&$($mutability)? self) @@ -151,6 +354,14 @@ macro_rules! make_value_visitor { { Ok(()) } + /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into. + /// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the + /// pointee type is the actual `T`. + #[inline(always)] + fn visit_box(&mut self, _v: &Self::V) -> InterpResult<'tcx> + { + Ok(()) + } /// Visits this value as an aggregate, you are getting an iterator yielding /// all the fields (still in an `InterpResult`, you have to do error handling yourself). /// Recurses into the fields. @@ -204,32 +415,74 @@ macro_rules! make_value_visitor { } fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> { - trace!("walk_value: type: {}", v.layout().ty); + let ty = v.layout().ty; + trace!("walk_value: type: {ty}"); // Special treatment for special types, where the (static) layout is not sufficient. - match *v.layout().ty.kind() { + match *ty.kind() { // If it is a trait object, switch to the real type that was used to create it. ty::Dynamic(..) => { - // immediate trait objects are not a thing - let op = v.to_op(self.ecx())?; + // unsized values are never immediate, so we can assert_mem_place + let op = v.to_op_for_read(self.ecx())?; let dest = op.assert_mem_place(); - let inner = self.ecx().unpack_dyn_trait(&dest)?.1; - trace!("walk_value: dyn object layout: {:#?}", inner.layout); + let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1; + trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); // recurse with the inner type - return self.visit_field(&v, 0, &Value::from_mem_place(inner)); + return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into())); }, // Slices do not need special handling here: they have `Array` field // placement with length 0, so we enter the `Array` case below which // indirectly uses the metadata to determine the actual length. + + // However, `Box`... let's talk about `Box`. + ty::Adt(def, ..) if def.is_box() => { + // `Box` is a hybrid primitive-library-defined type that one the one hand is + // a dereferenceable pointer, on the other hand has *basically arbitrary + // user-defined layout* since the user controls the 'allocator' field. So it + // cannot be treated like a normal pointer, since it does not fit into an + // `Immediate`. Yeah, it is quite terrible. But many visitors want to do + // something with "all boxed pointers", so we handle this mess for them. + // + // When we hit a `Box`, we do not do the usual `visit_aggregate`; instead, + // we (a) call `visit_box` on the pointer value, and (b) recurse on the + // allocator field. We also assert tons of things to ensure we do not miss + // any other fields. + + // `Box` has two fields: the pointer we care about, and the allocator. + assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields"); + let (unique_ptr, alloc) = + (v.project_field(self.ecx(), 0)?, v.project_field(self.ecx(), 1)?); + // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... + // (which means another 2 fields, the second of which is a `PhantomData`) + assert_eq!(unique_ptr.layout().fields.count(), 2); + let (nonnull_ptr, phantom) = ( + unique_ptr.project_field(self.ecx(), 0)?, + unique_ptr.project_field(self.ecx(), 1)?, + ); + assert!( + phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), + "2nd field of `Unique` should be PhantomData but is {:?}", + phantom.layout().ty, + ); + // ... that contains a `NonNull`... (gladly, only a single field here) + assert_eq!(nonnull_ptr.layout().fields.count(), 1); + let raw_ptr = nonnull_ptr.project_field(self.ecx(), 0)?; // the actual raw ptr + // ... whose only field finally is a raw ptr we can dereference. + self.visit_box(&raw_ptr)?; + + // The second `Box` field is the allocator, which we recursively check for validity + // like in regular structs. + self.visit_field(v, 1, &alloc)?; + } _ => {}, }; // Visit the fields of this value. match v.layout().fields { - FieldsShape::Primitive => {}, + FieldsShape::Primitive => {} FieldsShape::Union(fields) => { self.visit_union(v, fields)?; - }, + } FieldsShape::Arbitrary { ref offsets, .. } => { // FIXME: We collect in a vec because otherwise there are lifetime // errors: Projecting to a field needs access to `ecx`. @@ -239,17 +492,17 @@ macro_rules! make_value_visitor { }) .collect(); self.visit_aggregate(v, fields.into_iter())?; - }, + } FieldsShape::Array { .. } => { - // Let's get an mplace first. - let op = v.to_op(self.ecx())?; - let mplace = op.assert_mem_place(); + // Let's get an mplace (or immediate) first. + // This might `force_allocate` if `v` is a `PlaceTy`, but `place_index` does that anyway. + let op = v.to_op_for_proj(self.ecx())?; // Now we can go over all the fields. // This uses the *run-time length*, i.e., if we are a slice, // the dynamic info from the metadata is used. - let iter = self.ecx().mplace_array_fields(&mplace)? + let iter = self.ecx().operand_array_fields(&op)? .map(|f| f.and_then(|f| { - Ok(Value::from_mem_place(f)) + Ok($value_trait::from_op(&f)) })); self.visit_aggregate(v, iter)?; } @@ -259,7 +512,7 @@ macro_rules! make_value_visitor { // If this is a multi-variant layout, find the right variant and proceed // with *its* fields. Variants::Multiple { .. } => { - let op = v.to_op(self.ecx())?; + let op = v.to_op_for_read(self.ecx())?; let idx = self.read_discriminant(&op)?; let inner = v.project_downcast(self.ecx(), idx)?; trace!("walk_value: variant layout: {:#?}", inner.layout()); @@ -274,5 +527,5 @@ macro_rules! make_value_visitor { } } -make_value_visitor!(ValueVisitor,); -make_value_visitor!(MutValueVisitor, mut); +make_value_visitor!(ValueVisitor, Value,); +make_value_visitor!(MutValueVisitor, ValueMut, mut); diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 64a74e9d7e206..bba3e99f7b1f8 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -9,7 +9,7 @@ Rust MIR: a lowered representation of Rust. #![feature(control_flow_enum)] #![feature(decl_macro)] #![feature(exact_size_is_empty)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(is_some_with)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] @@ -30,6 +31,7 @@ extern crate tracing; extern crate rustc_middle; pub mod const_eval; +mod errors; pub mod interpret; pub mod transform; pub mod util; @@ -42,7 +44,6 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.try_destructure_const = |tcx, val| const_eval::try_destructure_const(tcx, val); providers.eval_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); const_eval::eval_to_valtree(tcx, param_env, raw) 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 069fbed36ee3a..0581f4919782d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -1,6 +1,6 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; @@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC use rustc_middle::mir::*; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; -use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable}; +use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; @@ -24,6 +24,7 @@ use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDro use super::resolver::FlowSensitiveAnalysis; use super::{ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; +use crate::errors::UnstableInStable; type QualifResults<'mir, 'tcx, Q> = rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>; @@ -311,7 +312,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { Status::Forbidden => None, }; - if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + if self.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { self.tcx.sess.miri_unleashed_feature(span, gate); return; } @@ -418,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } }; - self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_local(reborrowed_place_ref.local, ctx, location); self.visit_projection(reborrowed_place_ref, ctx, location); return; } @@ -431,7 +432,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; - self.visit_local(&reborrowed_place_ref.local, ctx, location); + self.visit_local(reborrowed_place_ref.local, ctx, location); self.visit_projection(reborrowed_place_ref, ctx, location); return; } @@ -445,6 +446,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), Rvalue::Use(_) + | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) | Rvalue::Discriminant(..) | Rvalue::Len(_) @@ -650,6 +652,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {} @@ -1026,23 +1029,5 @@ fn is_int_bool_or_char(ty: Ty<'_>) -> bool { fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo(); - ccx.tcx - .sess - .struct_span_err( - span, - &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()), - ) - .span_suggestion( - attr_span, - "if it is not part of the public API, make this function unstably const", - concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n'), - Applicability::HasPlaceholders, - ) - .span_suggestion( - attr_span, - "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks", - format!("#[rustc_allow_const_fn_unstable({})]\n", gate), - Applicability::MaybeIncorrect, - ) - .emit(); + ccx.tcx.sess.emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span }); } 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 0c587220cb772..1d083b0bf8268 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,7 +1,9 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::def_id::LocalDefId; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, +}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -20,6 +22,10 @@ use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; +use crate::errors::{ + MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrComparisonErr, RawPtrToIntErr, + StaticAccessErr, TransientMutBorrowErr, TransientMutBorrowErrRaw, +}; use crate::util::{call_kind, CallDesugaringKind, CallKind}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -155,8 +161,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { }); if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { - let span = - tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id)); + let span = tcx.def_span(data.impl_def_id); err.span_note(span, "impl defined here, but it is not `const`"); } } @@ -205,7 +210,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { match self_ty.kind() { FnDef(def_id, ..) => { - let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id)); + let span = tcx.def_span(*def_id); if ccx.tcx.is_const_fn_raw(*def_id) { span_bug!(span, "calling const FnDef errored when it shouldn't"); } @@ -294,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err.note(&format!("attempting to deref into `{}`", deref_target_ty)); // Check first whether the source is accessible (issue #87060) - if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() { + if tcx.sess.source_map().is_span_accessible(deref_target) { err.span_note(deref_target, "deref defined here"); } @@ -591,17 +596,17 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let raw = match self.0 { - hir::BorrowKind::Raw => "raw ", - hir::BorrowKind::Ref => "", - }; - - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()), - ) + let kind = ccx.const_kind(); + match self.0 { + hir::BorrowKind::Raw => ccx + .tcx + .sess + .create_feature_err(TransientMutBorrowErrRaw { span, kind }, sym::const_mut_refs), + hir::BorrowKind::Ref => ccx + .tcx + .sess + .create_feature_err(TransientMutBorrowErr { span, kind }, sym::const_mut_refs), + } } } @@ -622,12 +627,9 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()), - ) + ccx.tcx + .sess + .create_feature_err(MutDerefErr { span, kind: ccx.const_kind() }, sym::const_mut_refs) } } @@ -640,10 +642,7 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - ccx.tcx.sess.struct_span_err( - span, - "argument to `panic!()` in a const context must have type `&str`", - ) + ccx.tcx.sess.create_err(PanicNonStrErr { span }) } } @@ -658,15 +657,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = ccx - .tcx - .sess - .struct_span_err(span, "pointers cannot be reliably compared during const eval"); - err.note( - "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \ - for more information", - ); - err + ccx.tcx.sess.create_err(RawPtrComparisonErr { span }) } } @@ -702,15 +693,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = ccx - .tcx - .sess - .struct_span_err(span, "pointers cannot be cast to integers during const eval"); - err.note("at compile-time, pointers do not have an integer value"); - err.note( - "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior", - ); - err + ccx.tcx.sess.create_err(RawPtrToIntErr { span }) } } @@ -731,24 +714,11 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let mut err = struct_span_err!( - ccx.tcx.sess, + ccx.tcx.sess.create_err(StaticAccessErr { span, - E0013, - "{}s cannot refer to statics", - ccx.const_kind() - ); - err.help( - "consider extracting the value of the `static` to a `const`, and referring to that", - ); - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "`static` and `const` variables can refer to other `const` variables. \ - A `const` variable, however, cannot refer to a `static` variable.", - ); - err.help("To fix this, the value can be extracted to a `const` and then used."); - } - err + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()), + }) } } @@ -761,13 +731,7 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - struct_span_err!( - ccx.tcx.sess, - span, - E0625, - "thread-local statics cannot be \ - accessed at compile-time" - ) + ccx.tcx.sess.create_err(NonConstOpErr { span }) } } 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 6e5a0c813ac20..c2b4f6eca5ced 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -96,13 +96,13 @@ impl Qualif for HasMutInterior { } fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, + _cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>, _: SubstsRef<'tcx>, ) -> bool { // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. // It arises structurally for all other types. - Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type() + adt.is_unsafe_cell() } } @@ -226,7 +226,7 @@ impl Qualif for CustomEq { // because that component may be part of an enum variant (e.g., // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be // structural-match (`Option::None`). - traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some() + traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some() } fn in_adt_inherently<'tcx>( @@ -260,6 +260,8 @@ where in_place::<Q, _>(cx, in_local, place.as_ref()) } + Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()), + Rvalue::Use(operand) | Rvalue::Repeat(operand, _) | Rvalue::UnaryOp(_, operand) @@ -314,6 +316,7 @@ where ProjectionElem::Deref | ProjectionElem::Field(_, _) + | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(_, _) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index fd7febc17a3a7..60c1e4950292d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -199,6 +199,7 @@ where mir::Rvalue::Cast(..) | mir::Rvalue::ShallowInitBox(..) | mir::Rvalue::Use(..) + | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) | mir::Rvalue::Len(..) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 3595a488d0c5b..daa154576ae4b 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::traversal::ReversePostorderIter; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, List, TyCtxt, TypeVisitable}; use rustc_span::Span; use rustc_index::vec::{Idx, IndexVec}; @@ -106,7 +106,7 @@ struct Collector<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { - fn visit_local(&mut self, &index: &Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, index: Local, context: PlaceContext, location: Location) { 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) { @@ -361,7 +361,7 @@ impl<'tcx> Validator<'_, 'tcx> { return Err(Unpromotable); } } - ProjectionElem::Downcast(..) => { + ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { return Err(Unpromotable); } @@ -494,6 +494,10 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { self.validate_operand(operand)?; } + Rvalue::CopyForDeref(place) => { + let op = &Operand::Copy(*place); + self.validate_operand(op)? + } Rvalue::Discriminant(place) | Rvalue::Len(place) => { self.validate_place(place.as_ref())? @@ -856,7 +860,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { literal: ConstantKind::from_const(_const, tcx), })) }; - let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); + let blocks = self.source.basic_blocks.as_mut(); + let local_decls = &mut self.source.local_decls; let loc = candidate.location; let statement = &mut blocks[loc.block].statements[loc.statement_index]; match statement.kind { @@ -865,7 +870,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { Rvalue::Ref(ref mut region, borrow_kind, ref mut place), )) => { // Use the underlying local for this (necessarily interior) borrow. - let ty = local_decls.local_decls()[place.local].ty; + let ty = local_decls[place.local].ty; let span = statement.source_info.span; let ref_ty = tcx.mk_ref( diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 66d66ea951033..15e820f2d1941 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -7,14 +7,15 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, Local, Location, MirPass, - MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, - StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, + traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location, + MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, + Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, }; use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_mir_dataflow::impls::MaybeStorageLive; -use rustc_mir_dataflow::storage::always_live_locals; +use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; use rustc_target::abi::{Size, VariantIdx}; @@ -48,7 +49,7 @@ impl<'tcx> MirPass<'tcx> for Validator { let param_env = tcx.param_env(def_id); let mir_phase = self.mir_phase; - let always_live_locals = always_live_locals(body); + let always_live_locals = always_storage_live_locals(body); let storage_liveness = MaybeStorageLive::new(always_live_locals) .into_engine(tcx, body) .iterate_to_fixpoint() @@ -196,8 +197,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { - fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { - if self.body.local_decls.get(*local).is_none() { + fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { + if self.body.local_decls.get(local).is_none() { self.fail( location, format!("local {:?} has no corresponding declaration in `body.local_decls`", local), @@ -205,10 +206,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } if self.reachable_blocks.contains(location.block) && context.is_use() { - // Uses of locals must occur while the local's storage is allocated. + // We check that the local is live whenever it is used. Technically, violating this + // restriction is only UB and not actually indicative of not well-formed MIR. This means + // that an optimization which turns MIR that already has UB into MIR that fails this + // check is not necessarily wrong. However, we have no such optimizations at the moment, + // and so we include this check anyway to help us catch bugs. If you happen to write an + // optimization that might cause this to incorrectly fire, feel free to remove this + // check. self.storage_liveness.seek_after_primary_effect(location); let locals_with_storage = self.storage_liveness.get(); - if !locals_with_storage.contains(*local) { + if !locals_with_storage.contains(local) { self.fail(location, format!("use of local {:?}, which has no storage here", local)); } } @@ -216,7 +223,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. - if self.tcx.sess.opts.debugging_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered + if self.tcx.sess.opts.unstable_opts.validate_mir && self.mir_phase < MirPhase::DropsLowered { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { @@ -275,7 +282,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } }; - match parent_ty.ty.kind() { + let kind = match parent_ty.ty.kind() { + &ty::Opaque(def_id, substs) => { + self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind() + } + kind => kind, + }; + + match kind { ty::Tuple(fields) => { let Some(f_ty) = fields.get(f.as_usize()) else { fail_out_of_bounds(self, location); @@ -299,12 +313,39 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; check_equal(self, location, f_ty); } - ty::Generator(_, substs, _) => { - let substs = substs.as_generator(); - let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else { - fail_out_of_bounds(self, location); - return; + &ty::Generator(def_id, substs, _) => { + let f_ty = if let Some(var) = parent_ty.variant_index { + let gen_body = if def_id == self.body.source.def_id() { + self.body + } else { + self.tcx.optimized_mir(def_id) + }; + + let Some(layout) = gen_body.generator_layout() else { + self.fail(location, format!("No generator layout for {:?}", parent_ty)); + return; + }; + + let Some(&local) = layout.variant_fields[var].get(f) else { + fail_out_of_bounds(self, location); + return; + }; + + let Some(&f_ty) = layout.field_tys.get(local) else { + self.fail(location, format!("Out of bounds local {:?} for {:?}", local, parent_ty)); + return; + }; + + f_ty + } else { + let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { + fail_out_of_bounds(self, location); + return; + }; + + f_ty }; + check_equal(self, location, f_ty); } _ => { @@ -328,6 +369,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { { self.fail(location, format!("{:?}, has deref at the wrong place", place)); } + + self.super_place(place, cntxt, location); } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { @@ -339,7 +382,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; } match rvalue { - Rvalue::Use(_) => {} + Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {} Rvalue::Aggregate(agg_kind, _) => { let disallowed = match **agg_kind { AggregateKind::Array(..) => false, @@ -361,6 +404,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + Rvalue::Ref(..) => {} Rvalue::Len(p) => { let pty = p.ty(&self.body.local_decls, self.tcx).ty; check_kinds!( @@ -503,7 +547,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let a = operand.ty(&self.body.local_decls, self.tcx); check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..)); } - _ => {} + Rvalue::Cast(kind, operand, target_type) => { + match kind { + CastKind::Misc => { + let op_ty = operand.ty(self.body, self.tcx); + if op_ty.is_enum() { + self.fail( + location, + format!( + "enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}", + ), + ); + } + } + // Nothing to check here + CastKind::PointerFromExposedAddress + | CastKind::PointerExposeAddress + | CastKind::Pointer(_) => {} + } + } + Rvalue::Repeat(_, _) + | Rvalue::ThreadLocalRef(_) + | Rvalue::AddressOf(_, _) + | Rvalue::NullaryOp(_, _) + | Rvalue::Discriminant(_) => {} } self.super_rvalue(rvalue, location); } @@ -525,6 +592,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), ); } + if let Rvalue::CopyForDeref(place) = rvalue { + if !place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_some() + { + self.fail( + location, + "`CopyForDeref` should only be used for dereferenceable types", + ) + } + } // FIXME(JakobDegen): Check this for all rvalues, not just this one. if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue { // The sides of an assignment must not alias. Currently this just checks whether @@ -823,8 +899,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.super_terminator(terminator, location); } - fn visit_source_scope(&mut self, scope: &SourceScope) { - if self.body.source_scopes.get(*scope).is_none() { + fn visit_source_scope(&mut self, scope: SourceScope) { + if self.body.source_scopes.get(scope).is_none() { self.tcx.sess.diagnostic().delay_span_bug( self.body.span, &format!( diff --git a/compiler/rustc_const_eval/src/util/collect_writes.rs b/compiler/rustc_const_eval/src/util/collect_writes.rs index 9c56fd722bda6..8d92bb3593857 100644 --- a/compiler/rustc_const_eval/src/util/collect_writes.rs +++ b/compiler/rustc_const_eval/src/util/collect_writes.rs @@ -24,8 +24,8 @@ struct FindLocalAssignmentVisitor { } impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { - fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { - if self.needle != *local { + fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { + if self.needle != local { return; } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 33deadb32d447..2a801d0e70269 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -20,7 +20,7 @@ stable_deref_trait = "1.0.0" rayon = { version = "0.4.0", package = "rustc-rayon", optional = true } rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true } rustc-hash = "1.1.0" -smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } rustc_index = { path = "../rustc_index", package = "rustc_index" } bitflags = "1.2.1" measureme = "10.0.0" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 390a44d3f337d..0a2d2b4070904 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,6 +10,7 @@ #![feature(array_windows)] #![feature(associated_type_bounds)] #![feature(auto_traits)] +#![feature(cell_leak)] #![feature(control_flow_enum)] #![feature(extend_one)] #![feature(let_else)] diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index 26b26415eea0f..917416df6b867 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -1,6 +1,6 @@ use std::fs::File; use std::io; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use crate::owning_ref::StableAddress; @@ -45,3 +45,64 @@ impl Deref for Mmap { // export any function that can cause the `Vec` to be re-allocated. As such the address of the // bytes inside this `Vec` is stable. unsafe impl StableAddress for Mmap {} + +#[cfg(not(target_arch = "wasm32"))] +pub struct MmapMut(memmap2::MmapMut); + +#[cfg(target_arch = "wasm32")] +pub struct MmapMut(Vec<u8>); + +#[cfg(not(target_arch = "wasm32"))] +impl MmapMut { + #[inline] + pub fn map_anon(len: usize) -> io::Result<Self> { + let mmap = memmap2::MmapMut::map_anon(len)?; + Ok(MmapMut(mmap)) + } + + #[inline] + pub fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + + #[inline] + pub fn make_read_only(self) -> std::io::Result<Mmap> { + let mmap = self.0.make_read_only()?; + Ok(Mmap(mmap)) + } +} + +#[cfg(target_arch = "wasm32")] +impl MmapMut { + #[inline] + pub fn map_anon(len: usize) -> io::Result<Self> { + let data = Vec::with_capacity(len); + Ok(MmapMut(data)) + } + + #[inline] + pub fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + #[inline] + pub fn make_read_only(self) -> std::io::Result<Mmap> { + Ok(Mmap(self.0)) + } +} + +impl Deref for MmapMut { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &*self.0 + } +} + +impl DerefMut for MmapMut { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut *self.0 + } +} diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 88ff33b4d09a1..d8b26f9840b63 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -826,6 +826,24 @@ cfg_if! { } } } + } else if #[cfg(target_os = "macos")] { + pub fn get_resident_set_size() -> Option<usize> { + use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO}; + use std::mem; + const PROC_TASKINFO_SIZE: c_int = mem::size_of::<proc_taskinfo>() as c_int; + + unsafe { + let mut info: proc_taskinfo = mem::zeroed(); + let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void; + let pid = getpid() as c_int; + let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE); + if ret == PROC_TASKINFO_SIZE { + Some(info.pti_resident_size as usize) + } else { + None + } + } + } } else if #[cfg(unix)] { pub fn get_resident_set_size() -> Option<usize> { let field = 1; diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index feb82cb093818..cf0940df9e487 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -21,6 +21,7 @@ use crate::owning_ref::{Erased, OwningRef}; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; +use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; pub use std::sync::atomic::Ordering; pub use std::sync::atomic::Ordering::SeqCst; @@ -41,7 +42,6 @@ cfg_if! { } use std::ops::Add; - use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe}; /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc. /// It has explicit ordering arguments and is only intended for use with @@ -339,7 +339,10 @@ cfg_if! { t: T, for_each: impl Fn(T::Item) + Sync + Send, ) { - t.into_par_iter().for_each(for_each) + let ps: Vec<_> = t.into_par_iter().map(|i| catch_unwind(AssertUnwindSafe(|| for_each(i)))).collect(); + ps.into_iter().for_each(|p| if let Err(panic) = p { + resume_unwind(panic) + }); } pub type MetadataRef = OwningRef<Box<dyn Erased + Send + Sync>, [u8]>; @@ -536,6 +539,33 @@ impl<T> RwLock<T> { pub fn borrow_mut(&self) -> WriteGuard<'_, T> { self.write() } + + #[cfg(not(parallel_compiler))] + #[inline(always)] + pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> { + ReadGuard::clone(rg) + } + + #[cfg(parallel_compiler)] + #[inline(always)] + pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> { + ReadGuard::rwlock(&rg).read() + } + + #[cfg(not(parallel_compiler))] + #[inline(always)] + pub fn leak(&self) -> &T { + ReadGuard::leak(self.read()) + } + + #[cfg(parallel_compiler)] + #[inline(always)] + pub fn leak(&self) -> &T { + let guard = self.read(); + let ret = unsafe { &*(&*guard as *const T) }; + std::mem::forget(guard); + ret + } } // FIXME: Probably a bad idea diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index caa92e74808c0..f5b059793cf4b 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -29,7 +29,7 @@ use rustc_log::stdout_isatty; use rustc_metadata::locator; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; -use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS}; +use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; use rustc_session::cstore::MetadataLoader; use rustc_session::getopts; @@ -124,7 +124,7 @@ impl Callbacks for TimePassesCallbacks { // If a --prints=... option has been given, we don't print the "total" // time because it will mess up the --prints output. See #64339. self.time_passes = config.opts.prints.is_empty() - && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time); + && (config.opts.unstable_opts.time_passes || config.opts.unstable_opts.time); config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; } } @@ -248,7 +248,7 @@ fn run_compiler( let sopts = &compiler.session().opts; if sopts.describe_lints { let mut lint_store = rustc_lint::new_lint_store( - sopts.debugging_opts.no_interleave_lints, + sopts.unstable_opts.no_interleave_lints, compiler.session().unstable_options(), ); let registered_lints = @@ -342,7 +342,7 @@ fn run_compiler( return early_exit(); } - if sess.opts.debugging_opts.parse_only || sess.opts.debugging_opts.show_span.is_some() { + if sess.opts.unstable_opts.parse_only || sess.opts.unstable_opts.show_span.is_some() { return early_exit(); } @@ -371,13 +371,13 @@ fn run_compiler( queries.global_ctxt()?; - if sess.opts.debugging_opts.no_analysis { + if sess.opts.unstable_opts.no_analysis { return early_exit(); } queries.global_ctxt()?.peek_mut().enter(|tcx| { let result = tcx.analysis(()); - if sess.opts.debugging_opts.save_analysis { + if sess.opts.unstable_opts.save_analysis { let crate_name = queries.crate_name()?.peek().clone(); sess.time("save_analysis", || { save::process_crate( @@ -401,7 +401,7 @@ fn run_compiler( queries.ongoing_codegen()?; - if sess.opts.debugging_opts.print_type_sizes { + if sess.opts.unstable_opts.print_type_sizes { sess.code_stats.print_type_sizes(); } @@ -414,14 +414,14 @@ fn run_compiler( linker.link()? } - if sess.opts.debugging_opts.perf_stats { + if sess.opts.unstable_opts.perf_stats { sess.print_perf_stats(); } - if sess.opts.debugging_opts.print_fuel.is_some() { + if sess.opts.unstable_opts.print_fuel.is_some() { eprintln!( "Fuel used by {}: {}", - sess.opts.debugging_opts.print_fuel.as_ref().unwrap(), + sess.opts.unstable_opts.print_fuel.as_ref().unwrap(), sess.print_fuel.load(SeqCst) ); } @@ -576,7 +576,7 @@ fn show_content_with_pager(content: &str) { } pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { - if sess.opts.debugging_opts.link_only { + if sess.opts.unstable_opts.link_only { if let Input::File(file) = compiler.input() { // FIXME: #![crate_type] and #![crate_name] support not implemented yet sess.init_crate_types(collect_crate_types(sess, &[])); @@ -606,7 +606,7 @@ pub fn list_metadata( metadata_loader: &dyn MetadataLoader, input: &Input, ) -> Compilation { - if sess.opts.debugging_opts.ls { + if sess.opts.unstable_opts.ls { match *input { Input::File(ref ifile) => { let path = &(*ifile); @@ -849,10 +849,10 @@ Available lint options: }; println!("Lint checks provided by rustc:\n"); - println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); - println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); let print_lints = |lints: Vec<&Lint>| { + println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); + println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); for lint in lints { let name = lint.name_lower().replace('_', "-"); println!( @@ -884,11 +884,15 @@ Available lint options: }; println!("Lint groups provided by rustc:\n"); - println!(" {} sub-lints", padded("name")); - println!(" {} ---------", padded("----")); - println!(" {} all lints that are set to issue warnings", padded("warnings")); - let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| { + let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| { + println!(" {} sub-lints", padded("name")); + println!(" {} ---------", padded("----")); + + if all_warnings { + println!(" {} all lints that are set to issue warnings", padded("warnings")); + } + for (name, to) in lints { let name = name.to_lowercase().replace('_', "-"); let desc = to @@ -901,7 +905,7 @@ Available lint options: println!("\n"); }; - print_lint_groups(builtin_groups); + print_lint_groups(builtin_groups, true); match (loaded_plugins, plugin.len(), plugin_groups.len()) { (false, 0, _) | (false, _, 0) => { @@ -916,7 +920,7 @@ Available lint options: } if g > 0 { println!("Lint groups provided by plugins loaded by this crate:\n"); - print_lint_groups(plugin_groups); + print_lint_groups(plugin_groups, false); } } } @@ -924,7 +928,7 @@ Available lint options: fn describe_debug_flags() { println!("\nAvailable options:\n"); - print_flag_list("-Z", config::DB_OPTIONS); + print_flag_list("-Z", config::Z_OPTIONS); } fn describe_codegen_flags() { @@ -932,7 +936,7 @@ fn describe_codegen_flags() { print_flag_list("-C", config::CG_OPTIONS); } -fn print_flag_list<T>( +pub fn print_flag_list<T>( cmdline_opt: &str, flag_list: &[(&'static str, T, &'static str, &'static str)], ) { @@ -996,7 +1000,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS .iter() .map(|&(name, ..)| ('C', name)) - .chain(DB_OPTIONS.iter().map(|&(name, ..)| ('Z', name))) + .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name))) .find(|&(_, name)| *opt == name.replace('_', "-")) .map(|(flag, _)| format!("{}. Did you mean `-{} {}`?", e, flag, opt)), _ => None, diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index d507293ccb0d7..977318b85895e 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -644,4 +644,5 @@ E0788: include_str!("./error_codes/E0788.md"), // E0721, // `await` keyword // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. + E0789, // rustc_allowed_through_unstable_modules without stability attribute } diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md index 6d58e50ec8813..b1683cf4fc4ae 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -24,12 +24,12 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in #![feature(intrinsics)] extern "rust-intrinsic" { - fn atomic_fence(); // ok! + fn atomic_fence_seqcst(); // ok! } fn main() { unsafe { - atomic_fence(); + atomic_fence_seqcst(); } } ``` diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl new file mode 100644 index 0000000000000..645673ef47aeb --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -0,0 +1,18 @@ +borrowck-move-unsized = + cannot move a value of type `{$ty}` + .label = the size of `{$ty}` cannot be statically determined + +borrowck-higher-ranked-lifetime-error = + higher-ranked lifetime error + +borrowck-could-not-prove = + could not prove `{$predicate}` + +borrowck-could-not-normalize = + could not normalize `{$value}` + +borrowck-higher-ranked-subtype-error = + higher-ranked subtype error + +generic-does-not-live-long-enough = + `{$kind}` does not live long enough \ No newline at end of file diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl new file mode 100644 index 0000000000000..3f2ff86100160 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl @@ -0,0 +1,31 @@ +const-eval-unstable-in-stable = + const-stable function cannot use `#[feature({$gate})]` + .unstable-sugg = if it is not part of the public API, make this function unstably const + .bypass-sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks + +const-eval-thread-local-access = + thread-local statics cannot be accessed at compile-time + +const-eval-static-access = + {$kind}s cannot refer to statics + .help = consider extracting the value of the `static` to a `const`, and referring to that + .teach-note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. + .teach-help = To fix this, the value can be extracted to a `const` and then used. + +const-eval-raw-ptr-to-int = + pointers cannot be cast to integers during const eval + .note = at compile-time, pointers do not have an integer value + .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +const-eval-raw-ptr-comparison = + pointers cannot be reliably compared during const eval + .note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information + +const-eval-panic-non-str = argument to `panic!()` in a const context must have type `&str` + +const-eval-mut-deref = + mutation through a reference is not allowed in {$kind}s + +const-eval-transient-mut-borrow = mutable references are not allowed in {$kind}s + +const-eval-transient-mut-borrow-raw = raw mutable references are not allowed in {$kind}s diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl new file mode 100644 index 0000000000000..8d506a3ea8bbc --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl @@ -0,0 +1,5 @@ +expand-explain-doc-comment-outer = + outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match + +expand-explain-doc-comment-inner = + inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl new file mode 100644 index 0000000000000..e7e07093c0324 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -0,0 +1,400 @@ +lint-array-into-iter = + this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021 + .use-iter-suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity + .remove-into-iter-suggestion = or remove `.into_iter()` to iterate by value + .use-explicit-into-iter-suggestion = + or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + +lint-enum-intrinsics-mem-discriminant = + the return value of `mem::discriminant` is unspecified when called with a non-enum type + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + +lint-enum-intrinsics-mem-variant = + the return value of `mem::variant_count` is unspecified when called with a non-enum type + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + +lint-expectation = this lint expectation is unfulfilled + .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + +lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of text present in {$label} + .label = this {$label} contains {$count -> + [one] an invisible + *[other] invisible + } unicode text flow control {$count -> + [one] codepoint + *[other] codepoints + } + .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + .suggestion-remove = if their presence wasn't intentional, you can remove them + .suggestion-escape = if you want to keep them but make them visible in your source code, you can escape them + .no-suggestion-note-escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} + +lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better performance + .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary + +lint-query-instability = using `{$query}` can result in unstable query results + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +lint-tykind-kind = usage of `ty::TyKind::<kind>` + .suggestion = try using `ty::<kind>` directly + +lint-tykind = usage of `ty::TyKind` + .help = try using `Ty` instead + +lint-ty-qualified = usage of qualified `ty::{$ty}` + .suggestion = try importing it and using it unqualified + +lint-lintpass-by-hand = implementing `LintPass` by hand + .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead + +lint-non-existant-doc-keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` + .help = only existing keywords are allowed in core/std + +lint-diag-out-of-impl = + diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls + +lint-untranslatable-diag = diagnostics should be created using translatable messages + +lint-cstring-ptr = getting the inner pointer of a temporary `CString` + .as-ptr-label = this pointer will be invalid + .unwrap-label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + .help = for more information, see https://doc.rust-lang.org/reference/destructors.html + +lint-identifier-non-ascii-char = identifier contains non-ASCII characters + +lint-identifier-uncommon-codepoints = identifier contains uncommon Unicode codepoints + +lint-confusable-identifier-pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` + .label = this is where the previous identifier occurred + +lint-mixed-script-confusables = + the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables + .includes-note = the usage includes {$includes} + .note = please recheck to make sure their usages are indeed what you want + +lint-non-fmt-panic = panic message is not a string literal + .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021 + .more-info-note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> + .supports-fmt-note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here + .supports-fmt-suggestion = remove the `format!(..)` macro call + .display-suggestion = add a "{"{"}{"}"}" format string to `Display` the message + .debug-suggestion = + add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}` + .panic-suggestion = {$already_suggested -> + [true] or use + *[false] use + } std::panic::panic_any instead + +lint-non-fmt-panic-unused = + panic message contains {$count -> + [one] an unused + *[other] unused + } formatting {$count -> + [one] placeholder + *[other] placeholders + } + .note = this message is not used as a format string when given without arguments, but will be in Rust 2021 + .add-args-suggestion = add the missing {$count -> + [one] argument + *[other] arguments + } + .add-fmt-suggestion = or add a "{"{"}{"}"}" format string to use the message literally + +lint-non-fmt-panic-braces = + panic message contains {$count -> + [one] a brace + *[other] braces + } + .note = this message is not used as a format string, but will be in Rust 2021 + .suggestion = add a "{"{"}{"}"}" format string to use the message literally + +lint-non-camel-case-type = {$sort} `{$name}` should have an upper camel case name + .suggestion = convert the identifier to upper camel case + .label = should have an UpperCamelCase name + +lint-non-snake-case = {$sort} `{$name}` should have a snake case name + .rename-or-convert-suggestion = rename the identifier or convert it to a snake case raw identifier + .cannot-convert-note = `{$sc}` cannot be used as a raw identifier + .rename-suggestion = rename the identifier + .convert-suggestion = convert the identifier to snake case + .help = convert the identifier to snake case: `{$sc}` + .label = should have a snake_case name + +lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name + .suggestion = convert the identifier to upper case + .label = should have an UPPER_CASE name + +lint-noop-method-call = call to `.{$method}()` on a reference in this situation does nothing + .label = unnecessary method call + .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed + +lint-pass-by-value = passing `{$ty}` by reference + .suggestion = try passing by value + +lint-redundant-semicolons = + unnecessary trailing {$multiple -> + [true] semicolons + *[false] semicolon + } + .suggestion = remove {$multiple -> + [true] these semicolons + *[false] this semicolon + } + +lint-drop-trait-constraints = + bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped + +lint-drop-glue = + types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped + +lint-range-endpoint-out-of-range = range endpoint is out of range for `{$ty}` + .suggestion = use an inclusive range instead + +lint-overflowing-bin-hex = literal out of range for `{$ty}` + .negative-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` + .negative-becomes-note = and the value `-{$lit}` will become `{$actually}{$ty}` + .positive-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` + .suggestion = consider using the type `{$suggestion_ty}` instead + .help = consider using the type `{$suggestion_ty}` instead + +lint-overflowing-int = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + .help = consider using the type `{$suggestion_ty}` instead + +lint-only-cast-u8-to-char = only `u8` can be cast into `char` + .suggestion = use a `char` literal instead + +lint-overflowing-uint = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + +lint-overflowing-literal = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` + +lint-unused-comparisons = comparison is useless due to type limits + +lint-improper-ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe + .label = not FFI-safe + .note = the type is defined here + +lint-improper-ctypes-opaque = opaque types have no C equivalent + +lint-improper-ctypes-fnptr-reason = this function pointer has Rust-specific calling convention +lint-improper-ctypes-fnptr-help = consider using an `extern fn(...) -> ...` function pointer instead + +lint-improper-ctypes-tuple-reason = tuples have unspecified layout +lint-improper-ctypes-tuple-help = consider using a struct instead + +lint-improper-ctypes-str-reason = string slices have no C equivalent +lint-improper-ctypes-str-help = consider using `*const u8` and a length instead + +lint-improper-ctypes-dyn = trait objects have no C equivalent + +lint-improper-ctypes-slice-reason = slices have no C equivalent +lint-improper-ctypes-slice-help = consider using a raw pointer instead + +lint-improper-ctypes-128bit = 128-bit integers don't currently have a known stable ABI + +lint-improper-ctypes-char-reason = the `char` type has no C equivalent +lint-improper-ctypes-char-help = consider using `u32` or `libc::wchar_t` instead + +lint-improper-ctypes-non-exhaustive = this enum is non-exhaustive +lint-improper-ctypes-non-exhaustive-variant = this enum has non-exhaustive variants + +lint-improper-ctypes-enum-repr-reason = enum has no representation hint +lint-improper-ctypes-enum-repr-help = + consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +lint-improper-ctypes-struct-fieldless-reason = this struct has no fields +lint-improper-ctypes-struct-fieldless-help = consider adding a member to this struct + +lint-improper-ctypes-union-fieldless-reason = this union has no fields +lint-improper-ctypes-union-fieldless-help = consider adding a member to this union + +lint-improper-ctypes-struct-non-exhaustive = this struct is non-exhaustive +lint-improper-ctypes-union-non-exhaustive = this union is non-exhaustive + +lint-improper-ctypes-struct-layout-reason = this struct has unspecified layout +lint-improper-ctypes-struct-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + +lint-improper-ctypes-union-layout-reason = this union has unspecified layout +lint-improper-ctypes-union-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union + +lint-improper-ctypes-box = box cannot be represented as a single pointer + +lint-improper-ctypes-enum-phantomdata = this enum contains a PhantomData field + +lint-improper-ctypes-struct-zst = this struct contains only zero-sized fields + +lint-improper-ctypes-array-reason = passing raw arrays by value is not FFI-safe +lint-improper-ctypes-array-help = consider passing a pointer to the array + +lint-improper-ctypes-only-phantomdata = composed only of `PhantomData` + +lint-variant-size-differences = + enum variant is more than three times larger ({$largest} bytes) than the next largest + +lint-atomic-ordering-load = atomic loads cannot have `Release` or `AcqRel` ordering + .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +lint-atomic-ordering-store = atomic stores cannot have `Acquire` or `AcqRel` ordering + .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +lint-atomic-ordering-fence = memory fences cannot have `Relaxed` ordering + .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` + +lint-atomic-ordering-invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write + .label = invalid failure ordering + .help = consider using `Acquire` or `Relaxed` failure ordering instead + +lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering + .fail-label = `{$fail_ordering}` failure ordering + .success-label = `{$success_ordering}` success ordering + .suggestion = consider using `{$success_suggestion}` success ordering instead + +lint-unused-op = unused {$op} that must be used + .label = the {$op} produces a value + .suggestion = use `let _ = ...` to ignore the resulting value + +lint-unused-result = unused result of type `{$ty}` + +lint-unused-closure = + unused {$pre}{$count -> + [one] closure + *[other] closures + }{$post} that must be used + .note = closures are lazy and do nothing unless called + +lint-unused-generator = + unused {$pre}{$count -> + [one] generator + *[other] generator + }{$post} that must be used + .note = generators are lazy and do nothing unless resumed + +lint-unused-def = unused {$pre}`{$def}`{$post} that must be used + +lint-path-statement-drop = path statement drops value + .suggestion = use `drop` to clarify the intent + +lint-path-statement-no-effect = path statement with no effect + +lint-unused-delim = unnecessary {$delim} around {$item} + .suggestion = remove these {$delim} + +lint-unused-import-braces = braces around {$node} is unnecessary + +lint-unused-allocation = unnecessary allocation, use `&` instead +lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead + +lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}` + .suggestion = use `loop` + +lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty} + +lint-builtin-non-shorthand-field-patterns = the `{$ident}:` in this pattern is redundant + .suggestion = use shorthand field pattern + +lint-builtin-overridden-symbol-name = + the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +lint-builtin-overridden-symbol-section = + the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them + +lint-builtin-allow-internal-unsafe = + `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site + +lint-builtin-unsafe-block = usage of an `unsafe` block + +lint-builtin-unsafe-trait = declaration of an `unsafe` trait + +lint-builtin-unsafe-impl = implementation of an `unsafe` trait + +lint-builtin-no-mangle-fn = declaration of a `no_mangle` function +lint-builtin-export-name-fn = declaration of a function with `export_name` +lint-builtin-link-section-fn = declaration of a function with `link_section` + +lint-builtin-no-mangle-static = declaration of a `no_mangle` static +lint-builtin-export-name-static = declaration of a static with `export_name` +lint-builtin-link-section-static = declaration of a static with `link_section` + +lint-builtin-no-mangle-method = declaration of a `no_mangle` method +lint-builtin-export-name-method = declaration of a method with `export_name` + +lint-builtin-decl-unsafe-fn = declaration of an `unsafe` function +lint-builtin-decl-unsafe-method = declaration of an `unsafe` method +lint-builtin-impl-unsafe-method = implementation of an `unsafe` method + +lint-builtin-missing-doc = missing documentation for {$article} {$desc} + +lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `impl Copy` + +lint-builtin-missing-debug-impl = + type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation + +lint-builtin-anonymous-params = anonymous parameters are deprecated and will be removed in the next edition + .suggestion = try naming the parameter or explicitly ignoring it + +lint-builtin-deprecated-attr-link = use of deprecated attribute `{$name}`: {$reason}. See {$link} +lint-builtin-deprecated-attr-used = use of deprecated attribute `{$name}`: no longer used. +lint-builtin-deprecated-attr-default-suggestion = remove this attribute + +lint-builtin-unused-doc-comment = unused doc comment + .label = rustdoc does not generate documentation for {$kind} + .plain-help = use `//` for a plain comment + .block-help = use `/* */` for a plain comment + +lint-builtin-no-mangle-generic = functions generic over types or consts must be mangled + .suggestion = remove this attribute + +lint-builtin-const-no-mangle = const items should never be `#[no_mangle]` + .suggestion = try a static value + +lint-builtin-mutable-transmutes = + transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell + +lint-builtin-unstable-features = unstable feature + +lint-builtin-unreachable-pub = unreachable `pub` {$what} + .suggestion = consider restricting its visibility + .help = or consider exporting it for use by other crates + +lint-builtin-type-alias-bounds-help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases + +lint-builtin-type-alias-where-clause = where clauses are not enforced in type aliases + .suggestion = the clause will not be checked when the type alias is used, and should be removed + +lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not enforced in type aliases + .suggestion = the bound will not be checked when the type alias is used, and should be removed + +lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters + +lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprecated + .suggestion = use `..=` for an inclusive range + +lint-builtin-unnameable-test-items = cannot test inner items + +lint-builtin-keyword-idents = `{$kw}` is a keyword in the {$next} edition + .suggestion = you can use a raw identifier to stay compatible + +lint-builtin-explicit-outlives = outlives requirements can be inferred + .suggestion = remove {$count -> + [one] this bound + *[other] these bounds + } + +lint-builtin-incomplete-features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes + .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information + .help = consider using `min_{$name}` instead, which is more stable and complete + +lint-builtin-clashing-extern-same-name = `{$this_fi}` redeclared with a different signature + .previous-decl-label = `{$orig}` previously declared here + .mismatch-label = this signature doesn't match the previous declaration +lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with a different signature + .previous-decl-label = `{$orig}` previously declared here + .mismatch-label = this signature doesn't match the previous declaration + +lint-builtin-deref-nullptr = dereferencing a null pointer + .label = this code causes undefined behavior when executed + +lint-builtin-asm-labels = avoid using named labels in inline assembly diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl new file mode 100644 index 0000000000000..e4c9a4dad7b48 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -0,0 +1,151 @@ +-passes-previously-accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +-passes-see-issue = + see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information + +passes-outer-crate-level-attr = + crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + +passes-inner-crate-level-attr = + crate-level attribute should be in the root module + +passes-ignored-attr-with-macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "80564")} + +passes-ignored-attr = `#[{$sym}]` is ignored on struct fields and match arms + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "80564")} + +passes-inline-ignored-function-prototype = `#[inline]` is ignored on function prototypes + +passes-inline-ignored-constants = `#[inline]` is ignored on constants + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "65833")} + +passes-inline-not-fn-or-closure = attribute should be applied to function or closure + .label = not a function or closure + +passes-no-coverage-ignored-function-prototype = `#[no_coverage]` is ignored on function prototypes + +passes-no-coverage-propagate = + `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + +passes-no-coverage-fn-defn = `#[no_coverage]` may only be applied to function definitions + +passes-no-coverage-not-coverable = `#[no_coverage]` must be applied to coverable code + .label = not coverable code + +passes-should-be-applied-to-fn = attribute should be applied to a function definition + .label = not a function definition + +passes-naked-tracked-caller = cannot use `#[track_caller]` with `#[naked]` + +passes-should-be-applied-to-struct-enum = attribute should be applied to a struct or enum + .label = not a struct or enum + +passes-should-be-applied-to-trait = attribute should be applied to a trait + .label = not a trait + +passes-target-feature-on-statement = {passes-should-be-applied-to-fn} + .warn = {-passes-previously-accepted} + .label = {passes-should-be-applied-to-fn.label} + +passes-should-be-applied-to-static = attribute should be applied to a static + .label = not a static + +passes-doc-expect-str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] + +passes-doc-alias-empty = {$attr_str} attribute cannot have empty value + +passes-doc-alias-bad-char = {$char_} character isn't allowed in {$attr_str} + +passes-doc-alias-start-end = {$attr_str} cannot start or end with ' ' + +passes-doc-alias-bad-location = {$attr_str} isn't allowed on {$location} + +passes-doc-alias-not-an-alias = {$attr_str} is the same as the item's name + +passes-doc-alias-duplicated = doc alias is duplicated + .label = first defined here + +passes-doc-alias-not-string-literal = `#[doc(alias("a"))]` expects string literals + +passes-doc-alias-malformed = + doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + +passes-doc-keyword-empty-mod = `#[doc(keyword = "...")]` should be used on empty modules + +passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules + +passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier + +passes-doc-tuple-variadic-not-first = + `#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity + +passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks + +passes-doc-inline-conflict-first = this attribute... +passes-doc-inline-conflict-second = ...conflicts with this attribute +passes-doc-inline-conflict = conflicting doc inlining attributes + .help = remove one of the conflicting attributes + +passes-doc-inline-only-use = this attribute can only be applied to a `use` item + .label = only applicable on `use` items + .not-a-use-item-label = not a `use` item + .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information + +passes-doc-attr-not-crate-level = + `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute + +passes-attr-crate-level = this attribute can only be applied at the crate level + .suggestion = to apply to the crate, use an inner attribute + .help = to apply to the crate, use an inner attribute + .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information + +passes-doc-test-unknown = unknown `doc(test)` attribute `{$path}` + +passes-doc-test-takes-list = `#[doc(test(...)]` takes a list of attributes + +passes-doc-primitive = `doc(primitive)` should never have been stable + +passes-doc-test-unknown-any = unknown `doc` attribute `{$path}` + +passes-doc-test-unknown-spotlight = unknown `doc` attribute `{$path}` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no-op-note = `doc(spotlight)` is now a no-op + +passes-doc-test-unknown-include = unknown `doc` attribute `{$path}` + .suggestion = use `doc = include_str!` instead + +passes-doc-invalid = invalid `doc` attribute + +passes-pass-by-value = `pass_by_value` attribute should be applied to a struct, enum or type alias + .label = is not a struct, enum or type alias + +passes-allow-incoherent-impl = + `rustc_allow_incoherent_impl` attribute should be applied to impl items. + .label = the only currently supported targets are inherent methods + +passes-has-incoherent-inherent-impl = + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + .label = only adts, extern types and traits are supported + +passes-must-use-async = + `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within + .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` + +passes-must-use-no-effect = `#[must_use]` has no effect when applied to {$article} {$target} + +passes-must-not-suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait + .label = is not a struct, enum, or trait + +passes-cold = {passes-should-be-applied-to-fn} + .warn = {-passes-previously-accepted} + .label = {passes-should-be-applied-to-fn.label} + +passes-link = attribute should be applied to an `extern` block with non-Rust ABI + .warn = {-passes-previously-accepted} + .label = not an `extern` block diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl new file mode 100644 index 0000000000000..f8a750da93f8d --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl @@ -0,0 +1,21 @@ +privacy-field-is-private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private +privacy-field-is-private-is-update-syntax-label = field `{$field_name}` is private +privacy-field-is-private-label = private field + +privacy-item-is-private = {$kind} `{$descr}` is private + .label = private {$kind} +privacy-unnamed-item-is-private = {$kind} is private + .label = private {$kind} + +privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface + .label = can't leak {$vis_descr} {$kind} + .visibility-label = `{$descr}` declared as {$vis_descr} + +privacy-from-private-dep-in-public-interface = + {$kind} `{$descr}` from private dependency '{$krate}' in public interface + +private-in-public-lint = + {$vis_descr} {$kind} `{$descr}` in public interface (error {$kind -> + [trait] E0445 + *[other] E0446 + }) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 7211c05432698..6b961eaeb42af 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(once_cell)] #![feature(rustc_attrs)] #![feature(type_alias_impl_trait)] @@ -31,9 +31,15 @@ pub use unic_langid::{langid, LanguageIdentifier}; // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. fluent_messages! { + borrowck => "../locales/en-US/borrowck.ftl", + builtin_macros => "../locales/en-US/builtin_macros.ftl", + const_eval => "../locales/en-US/const_eval.ftl", + expand => "../locales/en-US/expand.ftl", + lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", + passes => "../locales/en-US/passes.ftl", + privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", - builtin_macros => "../locales/en-US/builtin_macros.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; @@ -258,18 +264,6 @@ pub enum SubdiagnosticMessage { FluentAttr(FluentId), } -impl SubdiagnosticMessage { - /// Create a `SubdiagnosticMessage` for the provided Fluent attribute. - pub fn attr(id: impl Into<FluentId>) -> Self { - SubdiagnosticMessage::FluentAttr(id.into()) - } - - /// Create a `SubdiagnosticMessage` for the provided Fluent identifier. - pub fn message(id: impl Into<FluentId>) -> Self { - SubdiagnosticMessage::FluentIdentifier(id.into()) - } -} - /// `From` impl that enables existing diagnostic calls to functions which now take /// `impl Into<SubdiagnosticMessage>` to continue to work as before. impl<S: Into<String>> From<S> for SubdiagnosticMessage { @@ -332,11 +326,6 @@ impl DiagnosticMessage { _ => panic!("expected non-translatable diagnostic message"), } } - - /// Create a `DiagnosticMessage` for the provided Fluent identifier. - pub fn new(id: impl Into<FluentId>) -> Self { - DiagnosticMessage::FluentIdentifier(id.into(), None) - } } /// `From` impl that enables existing diagnostic calls to functions which now take @@ -347,6 +336,27 @@ impl<S: Into<String>> From<S> for DiagnosticMessage { } } +/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but +/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the +/// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be +/// able to convert between these, as much as they'll be converted back into `DiagnosticMessage` +/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive. +impl Into<SubdiagnosticMessage> for DiagnosticMessage { + fn into(self) -> SubdiagnosticMessage { + match self { + DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s), + DiagnosticMessage::FluentIdentifier(id, None) => { + SubdiagnosticMessage::FluentIdentifier(id) + } + // There isn't really a sensible behaviour for this because it loses information but + // this is the most sensible of the behaviours. + DiagnosticMessage::FluentIdentifier(_, Some(attr)) => { + SubdiagnosticMessage::FluentAttr(attr) + } + } + } +} + /// A span together with some additional data. #[derive(Clone, Debug)] pub struct SpanLabel { diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 8955762605713..7d7e92c522922 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -13,6 +13,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } rustc_lint_defs = { path = "../rustc_lint_defs" } unicode-width = "0.1.4" atty = "0.2" diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index b8545139cecc1..7d7f3e1833576 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,14 +1,15 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticMessage, Level, MultiSpan, SubdiagnosticMessage, Substitution, - SubstitutionPart, SuggestionStyle, + CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, + SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::stable_map::FxHashMap; use rustc_error_messages::FluentValue; +use rustc_hir as hir; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{edition::Edition, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; @@ -39,9 +40,48 @@ pub trait IntoDiagnosticArg { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; } -impl IntoDiagnosticArg for String { +macro_rules! into_diagnostic_arg_using_display { + ($( $ty:ty ),+ $(,)?) => { + $( + impl IntoDiagnosticArg for $ty { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } + } + )+ + } +} + +into_diagnostic_arg_using_display!( + i8, + u8, + i16, + u16, + i32, + u32, + i64, + u64, + i128, + u128, + std::num::NonZeroU32, + hir::Target, + Edition, + Ident, +); + +impl IntoDiagnosticArg for bool { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self)) + if self { + DiagnosticArgValue::Str(Cow::Borrowed("true")) + } else { + DiagnosticArgValue::Str(Cow::Borrowed("false")) + } + } +} + +impl IntoDiagnosticArg for char { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self))) } } @@ -51,15 +91,15 @@ impl IntoDiagnosticArg for Symbol { } } -impl IntoDiagnosticArg for Ident { +impl<'a> IntoDiagnosticArg for &'a str { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { self.to_string().into_diagnostic_arg() } } -impl<'a> IntoDiagnosticArg for &'a str { +impl IntoDiagnosticArg for String { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() + DiagnosticArgValue::Str(Cow::Owned(self)) } } @@ -78,6 +118,16 @@ impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> { } } +impl IntoDiagnosticArg for hir::ConstContext { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + hir::ConstContext::ConstFn => "constant function", + hir::ConstContext::Static(_) => "static", + hir::ConstContext::Const => "constant", + })) + } +} + /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic]. #[rustc_diagnostic_item = "AddSubdiagnostic"] @@ -86,6 +136,14 @@ pub trait AddSubdiagnostic { fn add_to_diagnostic(self, diag: &mut Diagnostic); } +/// Trait implemented by lint types. This should not be implemented manually. Instead, use +/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. +#[rustc_diagnostic_item = "DecorateLint"] +pub trait DecorateLint<'a, G: EmissionGuarantee> { + /// Decorate and emit a lint. + fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>); +} + #[must_use] #[derive(Clone, Debug, Encodable, Decodable)] pub struct Diagnostic { @@ -286,7 +344,7 @@ impl Diagnostic { /// /// This span is *not* considered a ["primary span"][`MultiSpan`]; only /// the `Span` supplied when creating the diagnostic is primary. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self { self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); self @@ -395,7 +453,7 @@ impl Diagnostic { self } - pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self { + pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { self.highlighted_note(vec![ (format!("`{}` from trait: `", name), Style::NoStyle), (signature, Style::Highlight), @@ -405,7 +463,7 @@ impl Diagnostic { } /// Add a note attached to this diagnostic. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { self.sub(Level::Note, msg, MultiSpan::new(), None); self @@ -428,7 +486,7 @@ impl Diagnostic { /// Prints the span with a note above it. /// This is like [`Diagnostic::note()`], but it gets its own span. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_note<S: Into<MultiSpan>>( &mut self, sp: S, @@ -450,7 +508,7 @@ impl Diagnostic { } /// Add a warning attached to this diagnostic. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { self.sub(Level::Warning(None), msg, MultiSpan::new(), None); self @@ -458,7 +516,7 @@ impl Diagnostic { /// Prints the span with a warning above it. /// This is like [`Diagnostic::warn()`], but it gets its own span. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_warn<S: Into<MultiSpan>>( &mut self, sp: S, @@ -469,7 +527,7 @@ impl Diagnostic { } /// Add a help message attached to this diagnostic. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self @@ -483,7 +541,7 @@ impl Diagnostic { /// Prints the span with some help above it. /// This is like [`Diagnostic::help()`], but it gets its own span. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_help<S: Into<MultiSpan>>( &mut self, sp: S, @@ -513,6 +571,14 @@ impl Diagnostic { self } + /// Clear any existing suggestions. + pub fn clear_suggestions(&mut self) -> &mut Self { + if let Ok(suggestions) = &mut self.suggestions { + suggestions.clear(); + } + self + } + /// Helper for pushing to `self.suggestions`, if available (not disable). fn push_suggestion(&mut self, suggestion: CodeSuggestion) { if let Ok(suggestions) = &mut self.suggestions { diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 9e0a99849a3f4..9e68ee282e652 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -461,6 +461,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); + forward!(pub fn clear_suggestions(&mut self,) -> &mut Self); forward!(pub fn multipart_suggestion( &mut self, @@ -529,7 +530,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { applicability: Applicability, ) -> &mut Self); - forward!(pub fn set_primary_message(&mut self, msg: impl Into<String>) -> &mut Self); + forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self); forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); forward!(pub fn set_arg( @@ -589,3 +590,27 @@ macro_rules! struct_span_err { macro_rules! error_code { ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }}; } + +/// Wrapper around a `DiagnosticBuilder` for creating lints. +pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>); + +impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { + #[rustc_lint_diagnostics] + /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. + pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> { + self.0.set_primary_message(msg); + self.0.set_is_lint(); + self.0 + } + + /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`. + pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> { + LintDiagnosticBuilder(err) + } +} + +impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> { + pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> { + LintDiagnosticBuilder(self.0.forget_guarantee()) + } +} diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index a4cbc73978d5b..85ea8eb393782 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -63,7 +63,7 @@ impl HumanReadableErrorType { bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, teach: bool, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, ) -> EmitterWriter { let (short, color_config) = self.unzip(); @@ -76,7 +76,7 @@ impl HumanReadableErrorType { short, teach, color, - terminal_width, + diagnostic_width, macro_backtrace, ) } @@ -281,9 +281,19 @@ pub trait Emitter { let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle"); let value = match attr { Some(attr) => { - message.get_attribute(attr).expect("missing attribute in fluent message").value() + if let Some(attr) = message.get_attribute(attr) { + attr.value() + } else { + panic!("missing attribute `{attr}` in fluent message `{identifier}`") + } + } + None => { + if let Some(value) = message.value() { + value + } else { + panic!("missing value in fluent message `{identifier}`") + } } - None => message.value().expect("missing value in fluent message"), }; let mut err = vec![]; @@ -656,11 +666,6 @@ impl Emitter for SilentEmitter { } } -/// Maximum number of lines we will print for a multiline suggestion; arbitrary. -/// -/// This should be replaced with a more involved mechanism to output multiline suggestions that -/// more closely mimics the regular diagnostic output, where irrelevant code lines are elided. -pub const MAX_SUGGESTION_HIGHLIGHT_LINES: usize = 6; /// Maximum number of suggestions to be shown /// /// Arbitrary, but taken from trait import suggestion limit @@ -705,7 +710,7 @@ pub struct EmitterWriter { short_message: bool, teach: bool, ui_testing: bool, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, } @@ -725,7 +730,7 @@ impl EmitterWriter { fallback_bundle: LazyFallbackBundle, short_message: bool, teach: bool, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); @@ -737,7 +742,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, - terminal_width, + diagnostic_width, macro_backtrace, } } @@ -750,7 +755,7 @@ impl EmitterWriter { short_message: bool, teach: bool, colored: bool, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, ) -> EmitterWriter { EmitterWriter { @@ -761,7 +766,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, - terminal_width, + diagnostic_width, macro_backtrace, } } @@ -1610,7 +1615,7 @@ impl EmitterWriter { width_offset + annotated_file.multiline_depth + 1 }; - let column_width = if let Some(width) = self.terminal_width { + let column_width = if let Some(width) = self.diagnostic_width { width.saturating_sub(code_offset) } else if self.ui_testing { DEFAULT_COLUMN_WIDTH diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index d4d1491c16945..b8cd334b4c6c6 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -42,7 +42,7 @@ pub struct JsonEmitter { pretty: bool, ui_testing: bool, json_rendered: HumanReadableErrorType, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, } @@ -54,7 +54,7 @@ impl JsonEmitter { fallback_bundle: LazyFallbackBundle, pretty: bool, json_rendered: HumanReadableErrorType, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { @@ -66,7 +66,7 @@ impl JsonEmitter { pretty, ui_testing: false, json_rendered, - terminal_width, + diagnostic_width, macro_backtrace, } } @@ -76,7 +76,7 @@ impl JsonEmitter { json_rendered: HumanReadableErrorType, fluent_bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, ) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); @@ -87,7 +87,7 @@ impl JsonEmitter { fallback_bundle, pretty, json_rendered, - terminal_width, + diagnostic_width, macro_backtrace, ) } @@ -100,7 +100,7 @@ impl JsonEmitter { fallback_bundle: LazyFallbackBundle, pretty: bool, json_rendered: HumanReadableErrorType, - terminal_width: Option<usize>, + diagnostic_width: Option<usize>, macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { @@ -112,7 +112,7 @@ impl JsonEmitter { pretty, ui_testing: false, json_rendered, - terminal_width, + diagnostic_width, macro_backtrace, } } @@ -345,7 +345,7 @@ impl Diagnostic { je.fluent_bundle.clone(), je.fallback_bundle.clone(), false, - je.terminal_width, + je.diagnostic_width, je.macro_backtrace, ) .ui_testing(je.ui_testing) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 78b0892b3bc17..e59a74e380ae3 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -370,10 +370,10 @@ impl fmt::Display for ExplicitBug { impl error::Error for ExplicitBug {} pub use diagnostic::{ - AddSubdiagnostic, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, + AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee}; +pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. @@ -649,7 +649,7 @@ impl Handler { /// Attempting to `.emit()` the builder will only emit if either: /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_warn( &self, span: impl Into<MultiSpan>, @@ -678,7 +678,7 @@ impl Handler { } /// Construct a builder at the `Allow` level at the given `span` and with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_allow( &self, span: impl Into<MultiSpan>, @@ -691,7 +691,7 @@ impl Handler { /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// Also include a code. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_warn_with_code( &self, span: impl Into<MultiSpan>, @@ -708,7 +708,7 @@ impl Handler { /// Attempting to `.emit()` the builder will only emit if either: /// * `can_emit_warnings` is `true` /// * `is_force_warn` was set in `DiagnosticId::Lint` - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Warning(None), msg) } @@ -728,13 +728,13 @@ impl Handler { } /// Construct a builder at the `Allow` level with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Allow, msg) } /// Construct a builder at the `Expect` level with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_expect( &self, msg: impl Into<DiagnosticMessage>, @@ -744,7 +744,7 @@ impl Handler { } /// Construct a builder at the `Error` level at the given `span` and with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_err( &self, span: impl Into<MultiSpan>, @@ -756,7 +756,7 @@ impl Handler { } /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_err_with_code( &self, span: impl Into<MultiSpan>, @@ -770,7 +770,7 @@ impl Handler { /// Construct a builder at the `Error` level with the `msg`. // FIXME: This method should be removed (every error should have an associated error code). - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_err( &self, msg: impl Into<DiagnosticMessage>, @@ -785,7 +785,7 @@ impl Handler { } /// Construct a builder at the `Error` level with the `msg` and the `code`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_err_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -797,7 +797,7 @@ impl Handler { } /// Construct a builder at the `Warn` level with the `msg` and the `code`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_warn_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -809,7 +809,7 @@ impl Handler { } /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_fatal( &self, span: impl Into<MultiSpan>, @@ -821,7 +821,7 @@ impl Handler { } /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_span_fatal_with_code( &self, span: impl Into<MultiSpan>, @@ -834,19 +834,19 @@ impl Handler { } /// Construct a builder at the `Error` level with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { DiagnosticBuilder::new_fatal(self, msg) } /// Construct a builder at the `Help` level with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Help, msg) } /// Construct a builder at the `Note` level with the `msg`. - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_note_without_error( &self, msg: impl Into<DiagnosticMessage>, @@ -854,13 +854,13 @@ impl Handler { DiagnosticBuilder::new(self, Level::Note, msg) } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! { self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span); FatalError.raise() } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_fatal_with_code( &self, span: impl Into<MultiSpan>, @@ -871,7 +871,7 @@ impl Handler { FatalError.raise() } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_err( &self, span: impl Into<MultiSpan>, @@ -880,7 +880,7 @@ impl Handler { self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap() } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_err_with_code( &self, span: impl Into<MultiSpan>, @@ -893,12 +893,12 @@ impl Handler { ); } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) { self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span); } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn span_warn_with_code( &self, span: impl Into<MultiSpan>, @@ -1447,7 +1447,7 @@ impl HandlerInner { self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0), ) { (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), - (0, _) | (1, _) => {} + (0 | 1, _) => {} (count, as_bug) => panic!( "aborting after {} errors due to `-Z treat-err-as-bug={}`", count, as_bug, @@ -1558,7 +1558,7 @@ pub fn add_elided_lifetime_in_path_suggestion( insertion_span: Span, ) { diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n))); - if source_map.span_to_snippet(insertion_span).is_err() { + if !source_map.is_span_accessible(insertion_span) { // Do not try to suggest anything if generated by a proc-macro. return; } diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 45237ab2e9f25..05e5913baa0c7 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -22,5 +22,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_lexer = { path = "../rustc_lexer" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 245719bff1202..e1f19064d522f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; -use rustc_lint_defs::BuiltinLintDiagnostics; +use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics}; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session, SessionDiagnostic}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; @@ -988,6 +988,8 @@ pub struct ExtCtxt<'a> { pub expansions: FxHashMap<Span, Vec<String>>, /// Used for running pre-expansion lints on freshly loaded modules. pub(super) lint_store: LintStoreExpandDyn<'a>, + /// Used for storing lints generated during expansion, like `NAMED_ARGUMENTS_USED_POSITIONALLY` + pub buffered_early_lint: Vec<BufferedEarlyLint>, /// When we 'expand' an inert attribute, we leave it /// in the AST, but insert it here so that we know /// not to expand it again. @@ -1020,6 +1022,7 @@ impl<'a> ExtCtxt<'a> { force_mode: false, expansions: FxHashMap::default(), expanded_inert_attrs: MarkedAttrs::new(), + buffered_early_lint: vec![], } } @@ -1077,6 +1080,7 @@ impl<'a> ExtCtxt<'a> { self.current_expansion.id.expansion_cause() } + #[rustc_lint_diagnostics] pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -1101,9 +1105,11 @@ impl<'a> ExtCtxt<'a> { /// /// Compilation will be stopped in the near future (at the end of /// the macro expansion phase). + #[rustc_lint_diagnostics] pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.sess.parse_sess.span_diagnostic.span_err(sp, msg); } + #[rustc_lint_diagnostics] pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.sess.parse_sess.span_diagnostic.span_warn(sp, msg); } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index e73c31c98fe32..fa3e2a4a5b81c 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -57,6 +57,10 @@ impl<'a> ExtCtxt<'a> { P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None }) } + pub fn ty_infer(&self, span: Span) -> P<ast::Ty> { + self.ty(span, ast::TyKind::Infer) + } + pub fn ty_path(&self, path: ast::Path) -> P<ast::Ty> { self.ty(path.span, ast::TyKind::Path(None, path)) } @@ -140,11 +144,39 @@ impl<'a> ExtCtxt<'a> { ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) } } + pub fn lifetime_static(&self, span: Span) -> ast::Lifetime { + self.lifetime(span, Ident::new(kw::StaticLifetime, span)) + } + pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) } } + pub fn stmt_let_pat(&self, sp: Span, pat: P<ast::Pat>, ex: P<ast::Expr>) -> ast::Stmt { + let local = P(ast::Local { + pat, + ty: None, + id: ast::DUMMY_NODE_ID, + kind: LocalKind::Init(ex), + span: sp, + attrs: AttrVec::new(), + tokens: None, + }); + self.stmt_local(local, sp) + } + pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt { + self.stmt_let_ty(sp, mutbl, ident, None, ex) + } + + pub fn stmt_let_ty( + &self, + sp: Span, + mutbl: bool, + ident: Ident, + ty: Option<P<ast::Ty>>, + ex: P<ast::Expr>, + ) -> ast::Stmt { let pat = if mutbl { let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut); self.pat_ident_binding_mode(sp, ident, binding_mode) @@ -153,7 +185,7 @@ impl<'a> ExtCtxt<'a> { }; let local = P(ast::Local { pat, - ty: None, + ty, id: ast::DUMMY_NODE_ID, kind: LocalKind::Init(ex), span: sp, @@ -315,12 +347,16 @@ impl<'a> ExtCtxt<'a> { self.expr_lit(sp, ast::LitKind::Bool(value)) } - pub fn expr_vec(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> { + /// `[expr1, expr2, ...]` + pub fn expr_array(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> { self.expr(sp, ast::ExprKind::Array(exprs)) } - pub fn expr_vec_slice(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> { - self.expr_addr_of(sp, self.expr_vec(sp, exprs)) + + /// `&[expr1, expr2, ...]` + pub fn expr_array_ref(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> { + self.expr_addr_of(sp, self.expr_array(sp, exprs)) } + pub fn expr_str(&self, sp: Span, s: Symbol) -> P<ast::Expr> { self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked)) } @@ -484,6 +520,7 @@ impl<'a> ExtCtxt<'a> { self.expr( span, ast::ExprKind::Closure( + ast::ClosureBinder::NotPresent, ast::CaptureBy::Ref, ast::Async::No, ast::Movability::Movable, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 3cada37257085..2b941ec68098a 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -171,7 +171,7 @@ fn get_features( continue; } - if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() { + if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() { if allowed.iter().all(|f| name.as_str() != f) { struct_span_err!( span_handler, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 978f87b1d136e..93eeca5b2892b 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -564,7 +564,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { .resolver .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment); - if self.cx.sess.opts.debugging_opts.incremental_relative_spans { + if self.cx.sess.opts.unstable_opts.incremental_relative_spans { for (invoc, _) in invocations.iter_mut() { let expn_id = invoc.expansion_data.id; let parent_def = self.cx.resolver.invocation_parent(expn_id); diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 86ff110eec183..03b75d809a088 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -3,12 +3,13 @@ #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(if_let_guard)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(macro_metavar_expr)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] +#![feature(rustc_attrs)] #![feature(try_blocks)] #![recursion_limit = "256"] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f40c365cbcc18..3e9ddd6aec075 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -25,6 +25,7 @@ use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; @@ -345,7 +346,7 @@ fn expand_macro<'cx>( if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); } - + annotate_doc_comment(&mut err, sess.source_map(), span); // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { for lhs in lhses { @@ -453,7 +454,10 @@ pub fn compile_declarative_macro( Failure(token, msg) => { let s = parse_failure_msg(&token); let sp = token.span.substitute_dummy(def.span); - sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit(); + let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s); + err.span_label(sp, msg); + annotate_doc_comment(&mut err, sess.source_map(), sp); + err.emit(); return dummy_syn_ext(); } Error(sp, msg) => { @@ -590,6 +594,34 @@ pub fn compile_declarative_macro( (mk_syn_ext(expander), rule_spans) } +#[derive(SessionSubdiagnostic)] +enum ExplainDocComment { + #[label(expand::explain_doc_comment_inner)] + Inner { + #[primary_span] + span: Span, + }, + #[label(expand::explain_doc_comment_outer)] + Outer { + #[primary_span] + span: Span, + }, +} + +fn annotate_doc_comment( + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + sm: &SourceMap, + span: Span, +) { + if let Ok(src) = sm.span_to_snippet(span) { + if src.starts_with("///") || src.starts_with("/**") { + err.subdiagnostic(ExplainDocComment::Outer { span }); + } else if src.starts_with("//!") || src.starts_with("/*!") { + err.subdiagnostic(ExplainDocComment::Inner { span }); + } + } +} + fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 876faad33b678..0315d11634c6b 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -218,10 +218,9 @@ pub fn default_submod_path<'a>( "" }; - let mod_name = ident.name.to_string(); - let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); + let default_path_str = format!("{}{}.rs", relative_prefix, ident.name); let secondary_path_str = - format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR); + format!("{}{}{}mod.rs", relative_prefix, ident.name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = sess.source_map().file_exists(&default_path); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 1e4193a5a16cc..411d6be9c44f4 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -2,7 +2,7 @@ use crate::base::ExtCtxt; use rustc_ast as ast; use rustc_ast::token; -use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; +use rustc_ast::tokenstream::{self, Spacing::*, TokenStream}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -14,8 +14,8 @@ use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, kw, sym, Symbol}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; -use pm::bridge::{server, TokenTree}; -use pm::{Delimiter, Level, LineColumn, Spacing}; +use pm::bridge::{server, DelimSpan, ExpnGlobals, Group, Punct, TokenTree}; +use pm::{Delimiter, Level, LineColumn}; use std::ops::Bound; use std::{ascii, panic}; @@ -49,158 +49,170 @@ impl ToInternal<token::Delimiter> for Delimiter { } } -impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)> - for TokenTree<Group, Punct, Ident, Literal> +impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> + for Vec<TokenTree<TokenStream, Span, Ident, Literal>> { - fn from_internal( - ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>), - ) -> Self { + fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self { use rustc_ast::token::*; - let joint = spacing == Joint; - let Token { kind, span } = match tree { - tokenstream::TokenTree::Delimited(span, delim, tts) => { - let delimiter = pm::Delimiter::from_internal(delim); - return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false }); - } - tokenstream::TokenTree::Token(token) => token, - }; + // Estimate the capacity as `stream.len()` rounded up to the next power + // of two to limit the number of required reallocations. + let mut trees = Vec::with_capacity(stream.len().next_power_of_two()); + let mut cursor = stream.into_trees(); - macro_rules! tt { - ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => ( - TokenTree::$ty(self::$ty { - $($field $(: $value)*,)+ - span, - }) - ); - ($ty:ident::$method:ident($($value:expr),*)) => ( - TokenTree::$ty(self::$ty::$method($($value,)* span)) - ); - } - macro_rules! op { - ($a:expr) => { - tt!(Punct::new($a, joint)) + while let Some((tree, spacing)) = cursor.next_with_spacing() { + let joint = spacing == Joint; + let Token { kind, span } = match tree { + tokenstream::TokenTree::Delimited(span, delim, tts) => { + let delimiter = pm::Delimiter::from_internal(delim); + trees.push(TokenTree::Group(Group { + delimiter, + stream: Some(tts), + span: DelimSpan { + open: span.open, + close: span.close, + entire: span.entire(), + }, + })); + continue; + } + tokenstream::TokenTree::Token(token) => token, }; - ($a:expr, $b:expr) => {{ - stack.push(tt!(Punct::new($b, joint))); - tt!(Punct::new($a, true)) - }}; - ($a:expr, $b:expr, $c:expr) => {{ - stack.push(tt!(Punct::new($c, joint))); - stack.push(tt!(Punct::new($b, true))); - tt!(Punct::new($a, true)) - }}; - } - match kind { - Eq => op!('='), - Lt => op!('<'), - Le => op!('<', '='), - EqEq => op!('=', '='), - Ne => op!('!', '='), - Ge => op!('>', '='), - Gt => op!('>'), - AndAnd => op!('&', '&'), - OrOr => op!('|', '|'), - Not => op!('!'), - Tilde => op!('~'), - BinOp(Plus) => op!('+'), - BinOp(Minus) => op!('-'), - BinOp(Star) => op!('*'), - BinOp(Slash) => op!('/'), - BinOp(Percent) => op!('%'), - BinOp(Caret) => op!('^'), - BinOp(And) => op!('&'), - BinOp(Or) => op!('|'), - BinOp(Shl) => op!('<', '<'), - BinOp(Shr) => op!('>', '>'), - BinOpEq(Plus) => op!('+', '='), - BinOpEq(Minus) => op!('-', '='), - BinOpEq(Star) => op!('*', '='), - BinOpEq(Slash) => op!('/', '='), - BinOpEq(Percent) => op!('%', '='), - BinOpEq(Caret) => op!('^', '='), - BinOpEq(And) => op!('&', '='), - BinOpEq(Or) => op!('|', '='), - BinOpEq(Shl) => op!('<', '<', '='), - BinOpEq(Shr) => op!('>', '>', '='), - At => op!('@'), - Dot => op!('.'), - DotDot => op!('.', '.'), - DotDotDot => op!('.', '.', '.'), - DotDotEq => op!('.', '.', '='), - Comma => op!(','), - Semi => op!(';'), - Colon => op!(':'), - ModSep => op!(':', ':'), - RArrow => op!('-', '>'), - LArrow => op!('<', '-'), - FatArrow => op!('=', '>'), - Pound => op!('#'), - Dollar => op!('$'), - Question => op!('?'), - SingleQuote => op!('\''), - - Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()), - Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)), - Lifetime(name) => { - let ident = symbol::Ident::new(name, span).without_first_quote(); - stack.push(tt!(Ident::new(rustc.sess(), ident.name, false))); - tt!(Punct::new('\'', true)) - } - Literal(lit) => tt!(Literal { lit }), - DocComment(_, attr_style, data) => { - let mut escaped = String::new(); - for ch in data.as_str().chars() { - escaped.extend(ch.escape_debug()); - } - let stream = [ - Ident(sym::doc, false), - Eq, - TokenKind::lit(token::Str, Symbol::intern(&escaped), None), - ] - .into_iter() - .map(|kind| tokenstream::TokenTree::token(kind, span)) - .collect(); - stack.push(TokenTree::Group(Group { - delimiter: pm::Delimiter::Bracket, - stream, - span: DelimSpan::from_single(span), - flatten: false, + let mut op = |s: &str| { + assert!(s.is_ascii()); + trees.extend(s.as_bytes().iter().enumerate().map(|(idx, &ch)| { + TokenTree::Punct(Punct { ch, joint: joint || idx != s.len() - 1, span }) })); - if attr_style == ast::AttrStyle::Inner { - stack.push(tt!(Punct::new('!', false))); + }; + + match kind { + Eq => op("="), + Lt => op("<"), + Le => op("<="), + EqEq => op("=="), + Ne => op("!="), + Ge => op(">="), + Gt => op(">"), + AndAnd => op("&&"), + OrOr => op("||"), + Not => op("!"), + Tilde => op("~"), + BinOp(Plus) => op("+"), + BinOp(Minus) => op("-"), + BinOp(Star) => op("*"), + BinOp(Slash) => op("/"), + BinOp(Percent) => op("%"), + BinOp(Caret) => op("^"), + BinOp(And) => op("&"), + BinOp(Or) => op("|"), + BinOp(Shl) => op("<<"), + BinOp(Shr) => op(">>"), + BinOpEq(Plus) => op("+="), + BinOpEq(Minus) => op("-="), + BinOpEq(Star) => op("*="), + BinOpEq(Slash) => op("/="), + BinOpEq(Percent) => op("%="), + BinOpEq(Caret) => op("^="), + BinOpEq(And) => op("&="), + BinOpEq(Or) => op("|="), + BinOpEq(Shl) => op("<<="), + BinOpEq(Shr) => op(">>="), + At => op("@"), + Dot => op("."), + DotDot => op(".."), + DotDotDot => op("..."), + DotDotEq => op("..="), + Comma => op(","), + Semi => op(";"), + Colon => op(":"), + ModSep => op("::"), + RArrow => op("->"), + LArrow => op("<-"), + FatArrow => op("=>"), + Pound => op("#"), + Dollar => op("$"), + Question => op("?"), + SingleQuote => op("'"), + + Ident(name, false) if name == kw::DollarCrate => trees.push(TokenTree::Ident(Ident::dollar_crate(span))), + Ident(name, is_raw) => trees.push(TokenTree::Ident(Ident::new(rustc.sess(), name, is_raw, span))), + Lifetime(name) => { + let ident = symbol::Ident::new(name, span).without_first_quote(); + trees.extend([ + TokenTree::Punct(Punct { ch: b'\'', joint: true, span }), + TokenTree::Ident(Ident::new(rustc.sess(), ident.name, false, span)), + ]); + } + Literal(lit) => trees.push(TokenTree::Literal(self::Literal { lit, span })), + DocComment(_, attr_style, data) => { + let mut escaped = String::new(); + for ch in data.as_str().chars() { + escaped.extend(ch.escape_debug()); + } + let stream = [ + Ident(sym::doc, false), + Eq, + TokenKind::lit(token::Str, Symbol::intern(&escaped), None), + ] + .into_iter() + .map(|kind| tokenstream::TokenTree::token(kind, span)) + .collect(); + trees.push(TokenTree::Punct(Punct { ch: b'#', joint: false, span })); + if attr_style == ast::AttrStyle::Inner { + trees.push(TokenTree::Punct(Punct { ch: b'!', joint: false, span })); + } + trees.push(TokenTree::Group(Group { + delimiter: pm::Delimiter::Bracket, + stream: Some(stream), + span: DelimSpan::from_single(span), + })); } - tt!(Punct::new('#', false)) - } - Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { - TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span)) - } - Interpolated(nt) => { - TokenTree::Group(Group { - delimiter: pm::Delimiter::None, - stream: TokenStream::from_nonterminal_ast(&nt), - span: DelimSpan::from_single(span), - flatten: crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()), - }) - } + Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { + trees.push(TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span))) + } - OpenDelim(..) | CloseDelim(..) => unreachable!(), - Eof => unreachable!(), + Interpolated(nt) => { + let stream = TokenStream::from_nonterminal_ast(&nt); + // A hack used to pass AST fragments to attribute and derive + // macros as a single nonterminal token instead of a token + // stream. Such token needs to be "unwrapped" and not + // represented as a delimited group. + // FIXME: It needs to be removed, but there are some + // compatibility issues (see #73345). + if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()) { + trees.extend(Self::from_internal((stream, rustc))); + } else { + trees.push(TokenTree::Group(Group { + delimiter: pm::Delimiter::None, + stream: Some(stream), + span: DelimSpan::from_single(span), + })) + } + } + + OpenDelim(..) | CloseDelim(..) => unreachable!(), + Eof => unreachable!(), + } } + trees } } -impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> { +impl ToInternal<TokenStream> for TokenTree<TokenStream, Span, Ident, Literal> { fn to_internal(self) -> TokenStream { use rustc_ast::token::*; let (ch, joint, span) = match self { TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span), - TokenTree::Group(Group { delimiter, stream, span, .. }) => { - return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream) - .into(); + TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => { + return tokenstream::TokenTree::Delimited( + tokenstream::DelimSpan { open, close }, + delimiter.to_internal(), + stream.unwrap_or_default(), + ) + .into(); } TokenTree::Ident(self::Ident { sym, is_raw, span }) => { return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into(); @@ -233,28 +245,28 @@ impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> { }; let kind = match ch { - '=' => Eq, - '<' => Lt, - '>' => Gt, - '!' => Not, - '~' => Tilde, - '+' => BinOp(Plus), - '-' => BinOp(Minus), - '*' => BinOp(Star), - '/' => BinOp(Slash), - '%' => BinOp(Percent), - '^' => BinOp(Caret), - '&' => BinOp(And), - '|' => BinOp(Or), - '@' => At, - '.' => Dot, - ',' => Comma, - ';' => Semi, - ':' => Colon, - '#' => Pound, - '$' => Dollar, - '?' => Question, - '\'' => SingleQuote, + b'=' => Eq, + b'<' => Lt, + b'>' => Gt, + b'!' => Not, + b'~' => Tilde, + b'+' => BinOp(Plus), + b'-' => BinOp(Minus), + b'*' => BinOp(Star), + b'/' => BinOp(Slash), + b'%' => BinOp(Percent), + b'^' => BinOp(Caret), + b'&' => BinOp(And), + b'|' => BinOp(Or), + b'@' => At, + b'.' => Dot, + b',' => Comma, + b';' => Semi, + b':' => Colon, + b'#' => Pound, + b'$' => Dollar, + b'?' => Question, + b'\'' => SingleQuote, _ => unreachable!(), }; @@ -277,38 +289,6 @@ impl ToInternal<rustc_errors::Level> for Level { pub struct FreeFunctions; -#[derive(Clone)] -pub struct Group { - delimiter: Delimiter, - stream: TokenStream, - span: DelimSpan, - /// A hack used to pass AST fragments to attribute and derive macros - /// as a single nonterminal token instead of a token stream. - /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345). - flatten: bool, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct Punct { - ch: char, - // NB. not using `Spacing` here because it doesn't implement `Hash`. - joint: bool, - span: Span, -} - -impl Punct { - fn new(ch: char, joint: bool, span: Span) -> Punct { - const LEGAL_CHARS: &[char] = &[ - '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';', - ':', '#', '$', '?', '\'', - ]; - if !LEGAL_CHARS.contains(&ch) { - panic!("unsupported character `{:?}`", ch) - } - Punct { ch, joint, span } - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Ident { sym: Symbol, @@ -370,15 +350,13 @@ impl<'a, 'b> Rustc<'a, 'b> { } fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal { - Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) } + Literal { lit: token::Lit::new(kind, symbol, suffix), span: self.call_site } } } impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type Group = Group; - type Punct = Punct; type Ident = Ident; type Literal = Literal; type SourceFile = Lrc<SourceFile>; @@ -448,6 +426,10 @@ impl server::TokenStream for Rustc<'_, '_> { // We don't use `TokenStream::from_ast` as the tokenstream currently cannot // be recovered in the general case. match &expr.kind { + ast::ExprKind::Lit(l) if l.token.kind == token::Bool => { + Ok(tokenstream::TokenTree::token(token::Ident(l.token.symbol, false), l.span) + .into()) + } ast::ExprKind::Lit(l) => { Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into()) } @@ -471,7 +453,7 @@ impl server::TokenStream for Rustc<'_, '_> { fn from_token_tree( &mut self, - tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>, + tree: TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>, ) -> Self::TokenStream { tree.to_internal() } @@ -479,7 +461,7 @@ impl server::TokenStream for Rustc<'_, '_> { fn concat_trees( &mut self, base: Option<Self::TokenStream>, - trees: Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>>, + trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>>, ) -> Self::TokenStream { let mut builder = tokenstream::TokenStreamBuilder::new(); if let Some(base) = base { @@ -509,93 +491,8 @@ impl server::TokenStream for Rustc<'_, '_> { fn into_trees( &mut self, stream: Self::TokenStream, - ) -> Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> { - // FIXME: This is a raw port of the previous approach (which had a - // `TokenStreamIter` server-side object with a single `next` method), - // and can probably be optimized (for bulk conversion). - let mut cursor = stream.into_trees(); - let mut stack = Vec::new(); - let mut tts = Vec::new(); - loop { - let next = stack.pop().or_else(|| { - let next = cursor.next_with_spacing()?; - Some(TokenTree::from_internal((next, &mut stack, self))) - }); - match next { - Some(TokenTree::Group(group)) => { - // A hack used to pass AST fragments to attribute and derive - // macros as a single nonterminal token instead of a token - // stream. Such token needs to be "unwrapped" and not - // represented as a delimited group. - // FIXME: It needs to be removed, but there are some - // compatibility issues (see #73345). - if group.flatten { - tts.append(&mut self.into_trees(group.stream)); - } else { - tts.push(TokenTree::Group(group)); - } - } - Some(tt) => tts.push(tt), - None => return tts, - } - } - } -} - -impl server::Group for Rustc<'_, '_> { - fn new(&mut self, delimiter: Delimiter, stream: Option<Self::TokenStream>) -> Self::Group { - Group { - delimiter, - stream: stream.unwrap_or_default(), - span: DelimSpan::from_single(server::Span::call_site(self)), - flatten: false, - } - } - - fn delimiter(&mut self, group: &Self::Group) -> Delimiter { - group.delimiter - } - - fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { - group.stream.clone() - } - - fn span(&mut self, group: &Self::Group) -> Self::Span { - group.span.entire() - } - - fn span_open(&mut self, group: &Self::Group) -> Self::Span { - group.span.open - } - - fn span_close(&mut self, group: &Self::Group) -> Self::Span { - group.span.close - } - - fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) { - group.span = DelimSpan::from_single(span); - } -} - -impl server::Punct for Rustc<'_, '_> { - fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct { - Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self)) - } - - fn as_char(&mut self, punct: Self::Punct) -> char { - punct.ch - } - - fn spacing(&mut self, punct: Self::Punct) -> Spacing { - if punct.joint { Spacing::Joint } else { Spacing::Alone } - } - - fn span(&mut self, punct: Self::Punct) -> Self::Span { - punct.span - } - - fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct { - Punct { span, ..punct } + ) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Ident, Self::Literal>> { + FromInternal::from_internal((stream, self)) } } @@ -829,18 +726,6 @@ impl server::Span for Rustc<'_, '_> { } } - fn def_site(&mut self) -> Self::Span { - self.def_site - } - - fn call_site(&mut self) -> Self::Span { - self.call_site - } - - fn mixed_site(&mut self) -> Self::Span { - self.mixed_site - } - fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { self.sess().source_map().lookup_char_pos(span.lo()).file } @@ -926,3 +811,13 @@ impl server::Span for Rustc<'_, '_> { }) } } + +impl server::Server for Rustc<'_, '_> { + fn globals(&mut self) -> ExpnGlobals<Self::Span> { + ExpnGlobals { + def_site: self.def_site, + call_site: self.call_site, + mixed_site: self.mixed_site, + } + } +} diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 8b7153776e4dc..e44f060819633 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -136,7 +136,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: & let mut msp = MultiSpan::from_span(primary_span); for span_label in span_labels { let span = make_span(&file_text, &span_label.start, &span_label.end); - msp.push_span_label(span, span_label.label.to_string()); + msp.push_span_label(span, span_label.label); println!("span: {:?} label: {:?}", span, span_label.label); println!("text: {:?}", source_map.span_to_snippet(span)); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 099c40b215d99..2d24101b2d59a 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -186,6 +186,8 @@ declare_features! ( /// Allows some increased flexibility in the name resolution rules, /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120), None), + /// Allows `if/while p && let q = r && ...` chains. + (accepted, let_chains, "1.64.0", Some(53667), None), /// Allows `break {expr}` with a value inside `loop`s. (accepted, loop_break_value, "1.19.0", Some(37339), None), /// Allows use of `?` as the Kleene "at most one" operator in macros. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index b54f0ef361a8d..1018facebaed9 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -148,6 +148,8 @@ declare_features! ( /// below (it has to be checked before expansion possibly makes /// macros disappear). (active, allow_internal_unstable, "1.0.0", None, None), + /// Allows using anonymous lifetimes in argument-position impl-trait. + (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None), /// Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), /// Outputs useful `assert!` messages @@ -156,9 +158,6 @@ 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 `#[repr(no_niche)]` (an implementation detail of `rustc`, - /// it is not on path for eventual stabilization). - (active, no_niche, "1.42.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. @@ -331,6 +330,8 @@ declare_features! ( (active, cfg_target_thread_local, "1.7.0", Some(29594), None), /// Allow conditional compilation depending on rust version (active, cfg_version, "1.45.0", Some(64796), None), + /// Allows `for<...>` on closures and generators. + (active, closure_lifetime_binder, "1.64.0", Some(97362), None), /// Allows `#[track_caller]` on closures and generators. (active, closure_track_caller, "1.57.0", Some(87417), None), /// Allows to use the `#[cmse_nonsecure_entry]` attribute. @@ -423,8 +424,6 @@ declare_features! ( (active, label_break_value, "1.28.0", Some(48594), None), // Allows setting the threshold for the `large_assignments` lint. (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 `let...else` statements. (active, let_else, "1.56.0", Some(87335), None), /// Allows `#[link(..., cfg(..))]`. @@ -528,13 +527,6 @@ declare_features! ( (incomplete, unsized_locals, "1.30.0", Some(48055), None), /// Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - /// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields - /// that don't implement `Copy` as long as they don't have any drop glue. - /// This is checked recursively. On encountering type variable where no progress can be made, - /// `T: Copy` is used as a substitute for "no drop glue". - /// - /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. - (active, untagged_unions, "1.13.0", Some(55149), None), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (active, used_with_arg, "1.60.0", Some(93798), None), /// Allows `extern "wasm" fn` diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6fcdfe44d8f64..c806df8214586 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -512,6 +512,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ allow_internal_unsafe, Normal, template!(Word), WarnFollowing, "allow_internal_unsafe side-steps the unsafe_code lint", ), + rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing, + "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ + through unstable paths"), // ========================================================================== // Internal attributes: Type system related: diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 54626caaf53ea..2ddaf9201098e 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -180,6 +180,9 @@ declare_features! ( /// Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None, None), (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), + /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. + (removed, untagged_unions, "1.13.0", Some(55149), None, + Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")), /// Allows `#[unwind(..)]`. /// /// Permits specifying whether a function should permit unwinding or abort on unwind. diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 47ace7ca3a750..69ad623b7ea86 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" doctest = false [dependencies] +rustc_arena = { path = "../rustc_arena" } rustc_target = { path = "../rustc_target" } rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -16,5 +17,5 @@ rustc_span = { path = "../rustc_span" } rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } tracing = "0.1" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } odht = { version = "0.3.1", features = ["nightly"] } diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 5d1314ebb488d..44335b7f42ef9 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -9,9 +9,10 @@ macro_rules! arena_types { // HIR types [] hir_krate: rustc_hir::Crate<'tcx>, [] arm: rustc_hir::Arm<'tcx>, - [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, Span), + [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, rustc_span::Span), [] asm_template: rustc_ast::InlineAsmTemplatePiece, [] attribute: rustc_ast::Attribute, + [] closure: rustc_hir::Closure<'tcx>, [] block: rustc_hir::Block<'tcx>, [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>, [] body: rustc_hir::Body<'tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a7fc59255d79a..48a41c8bd245a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -922,6 +922,17 @@ pub struct Crate<'hir> { pub hir_hash: Fingerprint, } +#[derive(Debug, HashStable_Generic)] +pub struct Closure<'hir> { + pub binder: ClosureBinder, + pub capture_clause: CaptureBy, + pub bound_generic_params: &'hir [GenericParam<'hir>], + pub fn_decl: &'hir FnDecl<'hir>, + pub body: BodyId, + pub fn_decl_span: Span, + pub movability: Option<Movability>, +} + /// A block of statements `{ .. }`, which may have a label (in this case the /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of /// the `rules` being anything but `DefaultBlock`. @@ -1316,6 +1327,8 @@ pub struct Local<'hir> { pub ty: Option<&'hir Ty<'hir>>, /// Initializer expression to set the value, if any. pub init: Option<&'hir Expr<'hir>>, + /// Else block for a `let...else` binding. + pub els: Option<&'hir Block<'hir>>, pub hir_id: HirId, pub span: Span, /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop @@ -1438,18 +1451,8 @@ impl<'hir> Body<'hir> { } /// The type of source expression that caused this generator to be created. -#[derive( - Clone, - PartialEq, - PartialOrd, - Eq, - Hash, - HashStable_Generic, - Encodable, - Decodable, - Debug, - Copy -)] +#[derive(Clone, PartialEq, PartialOrd, Eq, Hash, Debug, Copy)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum GeneratorKind { /// An explicit `async` block or the body of an async function. Async(AsyncGeneratorKind), @@ -1481,18 +1484,8 @@ impl GeneratorKind { /// /// This helps error messages but is also used to drive coercions in /// type-checking (see #60424). -#[derive( - Clone, - PartialEq, - PartialOrd, - Eq, - Hash, - HashStable_Generic, - Encodable, - Decodable, - Debug, - Copy -)] +#[derive(Clone, PartialEq, PartialOrd, Eq, Hash, Debug, Copy)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum AsyncGeneratorKind { /// An explicit `async` block written by the user. Block, @@ -1595,6 +1588,9 @@ impl fmt::Display for ConstContext { } } +// NOTE: `IntoDiagnosticArg` impl for `ConstContext` lives in `rustc_errors` +// due to a cyclical dependency between hir that crate. + /// A literal. pub type Lit = Spanned<LitKind>; @@ -1828,6 +1824,14 @@ impl Expr<'_> { _ => false, } } + + pub fn method_ident(&self) -> Option<Ident> { + match self.kind { + ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), + ExprKind::Unary(_, expr) | ExprKind::AddrOf(.., expr) => expr.method_ident(), + _ => None, + } + } } /// Checks if the specified expression is a built-in range literal. @@ -1930,14 +1934,7 @@ pub enum ExprKind<'hir> { /// /// This may also be a generator literal or an `async block` as indicated by the /// `Option<Movability>`. - Closure { - capture_clause: CaptureBy, - bound_generic_params: &'hir [GenericParam<'hir>], - fn_decl: &'hir FnDecl<'hir>, - body: BodyId, - fn_decl_span: Span, - movability: Option<Movability>, - }, + Closure(&'hir Closure<'hir>), /// A block (e.g., `'label: { ... }`). Block(&'hir Block<'hir>, Option<Label>), @@ -2715,6 +2712,17 @@ impl FnRetTy<'_> { } } +/// Represents `for<...>` binder before a closure +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum ClosureBinder { + /// Binder is not specified. + Default, + /// Binder is specified. + /// + /// Span points to the whole `for<...>`. + For { span: Span }, +} + #[derive(Encodable, Debug, HashStable_Generic)] pub struct Mod<'hir> { pub spans: ModSpans, @@ -3326,7 +3334,6 @@ pub enum Node<'hir> { Ty(&'hir Ty<'hir>), TypeBinding(&'hir TypeBinding<'hir>), TraitRef(&'hir TraitRef<'hir>), - Binding(&'hir Pat<'hir>), Pat(&'hir Pat<'hir>), Arm(&'hir Arm<'hir>), Block(&'hir Block<'hir>), @@ -3378,7 +3385,6 @@ impl<'hir> Node<'hir> { | Node::Block(..) | Node::Ctor(..) | Node::Pat(..) - | Node::Binding(..) | Node::Arm(..) | Node::Local(..) | Node::Crate(..) @@ -3481,7 +3487,7 @@ impl<'hir> Node<'hir> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { rustc_data_structures::static_assert_size!(super::Block<'static>, 48); - rustc_data_structures::static_assert_size!(super::Expr<'static>, 64); + rustc_data_structures::static_assert_size!(super::Expr<'static>, 56); rustc_data_structures::static_assert_size!(super::Pat<'static>, 88); rustc_data_structures::static_assert_size!(super::QPath<'static>, 24); rustc_data_structures::static_assert_size!(super::Ty<'static>, 72); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e68274e2ad978..d00b65da7e6a5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -19,7 +19,7 @@ //! - Example: Examine each expression to look for its type and do some check or other. //! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to //! `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use -//! `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your +//! `tcx.hir().visit_all_item_likes_in_crate(&mut visitor)`. Within your //! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke //! `intravisit::walk_expr()` to keep walking the subparts). //! - Pro: Visitor methods for any kind of HIR node, not just item-like things. @@ -65,7 +65,6 @@ //! example generator inference, and possibly also HIR borrowck. use crate::hir::*; -use crate::itemlikevisit::ParItemLikeVisitor; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; use rustc_span::symbol::{Ident, Symbol}; @@ -76,29 +75,6 @@ pub trait IntoVisitor<'hir> { fn into_visitor(&self) -> Self::Visitor; } -pub struct ParDeepVisitor<V>(pub V); - -impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V> -where - V: IntoVisitor<'hir>, -{ - fn visit_item(&self, item: &'hir Item<'hir>) { - self.0.into_visitor().visit_item(item); - } - - fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>) { - self.0.into_visitor().visit_trait_item(trait_item); - } - - fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>) { - self.0.into_visitor().visit_impl_item(impl_item); - } - - fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>) { - self.0.into_visitor().visit_foreign_item(foreign_item); - } -} - #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// `#[xxx] pub async/const/extern "Abi" fn foo()` @@ -214,7 +190,7 @@ use nested_filter::NestedFilter; /// (this is why the module is called `intravisit`, to distinguish it /// from the AST's `visit` module, which acts differently). If you /// simply want to visit all items in the crate in some order, you -/// should call `Crate::visit_all_items`. Otherwise, see the comment +/// should call `tcx.hir().visit_all_item_likes_in_crate`. Otherwise, see the comment /// on `visit_nested_item` for details on how to visit nested items. /// /// If you want to ensure that your code handles every variant @@ -496,6 +472,9 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) { walk_list!(visitor, visit_expr, &local.init); visitor.visit_id(local.hir_id); visitor.visit_pat(&local.pat); + if let Some(els) = local.els { + visitor.visit_block(els); + } walk_list!(visitor, visit_ty, &local.ty); } @@ -949,7 +928,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<' FnKind::ItemFn(_, generics, ..) => { visitor.visit_generics(generics); } - FnKind::Method(..) | FnKind::Closure => {} + FnKind::Closure | FnKind::Method(..) => {} } } @@ -1168,14 +1147,15 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprKind::Closure { + ExprKind::Closure(&Closure { + binder: _, bound_generic_params, - ref fn_decl, + fn_decl, body, capture_clause: _, fn_decl_span: _, movability: _, - } => { + }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) } diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs deleted file mode 100644 index a490268dc9f94..0000000000000 --- a/compiler/rustc_hir/src/itemlikevisit.rs +++ /dev/null @@ -1,9 +0,0 @@ -use super::{ForeignItem, ImplItem, Item, TraitItem}; - -/// A parallel variant of `ItemLikeVisitor`. -pub trait ParItemLikeVisitor<'hir> { - fn visit_item(&self, item: &'hir Item<'hir>); - fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>); - fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>); - fn visit_foreign_item(&self, foreign_item: &'hir ForeignItem<'hir>); -} diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index d845c433d8c5f..0f9e6fa7b9895 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -18,6 +18,8 @@ extern crate rustc_macros; #[macro_use] extern crate rustc_data_structures; +extern crate self as rustc_hir; + mod arena; pub mod def; pub mod def_path_hash_map; @@ -27,7 +29,6 @@ pub use rustc_span::def_id; mod hir; pub mod hir_id; pub mod intravisit; -pub mod itemlikevisit; pub mod lang_items; pub mod pat_util; mod stable_hash_impls; @@ -42,3 +43,5 @@ pub use hir_id::*; pub use lang_items::{LangItem, LanguageItems}; pub use stable_hash_impls::HashStableContext; pub use target::{MethodKind, Target}; + +arena_types!(rustc_arena::declare_arena); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7bf91df9f760b..18b671d410dc7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -6,6 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir as hir; +use rustc_hir::LifetimeParamKind; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term}; use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; use rustc_span::source_map::SourceMap; @@ -59,7 +60,7 @@ impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), + Nested::BodyParamPat(id, i) => state.print_pat(self.body(id).params[i].pat), } } } @@ -74,37 +75,37 @@ pub struct State<'a> { impl<'a> State<'a> { pub fn print_node(&mut self, node: Node<'_>) { match node { - Node::Param(a) => self.print_param(&a), - Node::Item(a) => self.print_item(&a), - Node::ForeignItem(a) => self.print_foreign_item(&a), + Node::Param(a) => self.print_param(a), + Node::Item(a) => self.print_item(a), + Node::ForeignItem(a) => self.print_foreign_item(a), Node::TraitItem(a) => self.print_trait_item(a), Node::ImplItem(a) => self.print_impl_item(a), - Node::Variant(a) => self.print_variant(&a), - Node::AnonConst(a) => self.print_anon_const(&a), - Node::Expr(a) => self.print_expr(&a), - Node::Stmt(a) => self.print_stmt(&a), - Node::PathSegment(a) => self.print_path_segment(&a), - Node::Ty(a) => self.print_type(&a), - Node::TypeBinding(a) => self.print_type_binding(&a), - Node::TraitRef(a) => self.print_trait_ref(&a), - Node::Binding(a) | Node::Pat(a) => self.print_pat(&a), - Node::Arm(a) => self.print_arm(&a), + Node::Variant(a) => self.print_variant(a), + Node::AnonConst(a) => self.print_anon_const(a), + Node::Expr(a) => self.print_expr(a), + Node::Stmt(a) => self.print_stmt(a), + Node::PathSegment(a) => self.print_path_segment(a), + Node::Ty(a) => self.print_type(a), + Node::TypeBinding(a) => self.print_type_binding(a), + Node::TraitRef(a) => self.print_trait_ref(a), + Node::Pat(a) => self.print_pat(a), + Node::Arm(a) => self.print_arm(a), Node::Infer(_) => self.word("_"), Node::Block(a) => { // Containing cbox, will be closed by print-block at `}`. self.cbox(INDENT_UNIT); // Head-ibox, will be closed by print-block after `{`. self.ibox(0); - self.print_block(&a) + self.print_block(a); } - Node::Lifetime(a) => self.print_lifetime(&a), + Node::Lifetime(a) => self.print_lifetime(a), Node::GenericParam(_) => panic!("cannot print Node::GenericParam"), Node::Field(_) => panic!("cannot print Node::Field"), // These cases do not carry enough information in the // `hir_map` to reconstruct their full structure for pretty // printing. Node::Ctor(..) => panic!("cannot print isolated Ctor"), - Node::Local(a) => self.print_local_decl(&a), + Node::Local(a) => self.print_local_decl(a), Node::Crate(..) => panic!("cannot print Crate"), } } @@ -266,7 +267,7 @@ impl<'a> State<'a> { } pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) { - self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span) + self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span); } pub fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) { @@ -287,9 +288,9 @@ impl<'a> State<'a> { self.maybe_print_comment(ty.span.lo()); self.ibox(0); match ty.kind { - hir::TyKind::Slice(ref ty) => { + hir::TyKind::Slice(ty) => { self.word("["); - self.print_type(&ty); + self.print_type(ty); self.word("]"); } hir::TyKind::Ptr(ref mt) => { @@ -304,23 +305,16 @@ impl<'a> State<'a> { hir::TyKind::Never => { self.word("!"); } - hir::TyKind::Tup(ref elts) => { + hir::TyKind::Tup(elts) => { self.popen(); - self.commasep(Inconsistent, &elts, |s, ty| s.print_type(&ty)); + self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty)); if elts.len() == 1 { self.word(","); } self.pclose(); } - hir::TyKind::BareFn(ref f) => { - self.print_ty_fn( - f.abi, - f.unsafety, - &f.decl, - None, - &f.generic_params, - f.param_names, - ); + hir::TyKind::BareFn(f) => { + self.print_ty_fn(f.abi, f.unsafety, f.decl, None, f.generic_params, f.param_names); } hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), @@ -344,9 +338,9 @@ impl<'a> State<'a> { self.print_lifetime(lifetime); } } - hir::TyKind::Array(ref ty, ref length) => { + hir::TyKind::Array(ty, ref length) => { self.word("["); - self.print_type(&ty); + self.print_type(ty); self.word("; "); self.print_array_length(length); self.word("]"); @@ -373,7 +367,7 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(ref decl, ref arg_names, ref generics) => { + hir::ForeignItemKind::Fn(decl, arg_names, generics) => { self.head(""); self.print_fn( decl, @@ -392,14 +386,14 @@ impl<'a> State<'a> { self.word(";"); self.end() // end the outer fn box } - hir::ForeignItemKind::Static(ref t, m) => { + hir::ForeignItemKind::Static(t, m) => { self.head("static"); if m == hir::Mutability::Mut { self.word_space("mut"); } self.print_ident(item.ident); self.word_space(":"); - self.print_type(&t); + self.print_type(t); self.word(";"); self.end(); // end the head-ibox self.end() // end the outer cbox @@ -442,7 +436,7 @@ impl<'a> State<'a> { ) { self.word_space("type"); self.print_ident(ident); - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); if let Some(bounds) = bounds { self.print_bounds(":", bounds); } @@ -463,7 +457,7 @@ impl<'a> State<'a> { ) { self.head("type"); self.print_ident(item.ident); - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); self.end(); // end the inner ibox self.print_where_clause(generics); @@ -494,7 +488,7 @@ impl<'a> State<'a> { self.end(); // end inner head-block self.end(); // end outer head-block } - hir::ItemKind::Use(ref path, kind) => { + hir::ItemKind::Use(path, kind) => { self.head("use"); self.print_path(path, false); @@ -513,14 +507,14 @@ impl<'a> State<'a> { self.end(); // end inner head-block self.end(); // end outer head-block } - hir::ItemKind::Static(ref ty, m, expr) => { + hir::ItemKind::Static(ty, m, expr) => { self.head("static"); if m == hir::Mutability::Mut { self.word_space("mut"); } self.print_ident(item.ident); self.word_space(":"); - self.print_type(&ty); + self.print_type(ty); self.space(); self.end(); // end the head-ibox @@ -529,11 +523,11 @@ impl<'a> State<'a> { self.word(";"); self.end(); // end the outer cbox } - hir::ItemKind::Const(ref ty, expr) => { + hir::ItemKind::Const(ty, expr) => { self.head("const"); self.print_ident(item.ident); self.word_space(":"); - self.print_type(&ty); + self.print_type(ty); self.space(); self.end(); // end the head-ibox @@ -542,10 +536,10 @@ impl<'a> State<'a> { self.word(";"); self.end(); // end the outer cbox } - hir::ItemKind::Fn(ref sig, ref param_names, body) => { + hir::ItemKind::Fn(ref sig, param_names, body) => { self.head(""); self.print_fn( - &sig.decl, + sig.decl, sig.header, Some(item.ident.name), param_names, @@ -578,22 +572,22 @@ impl<'a> State<'a> { } self.bclose(item.span); } - hir::ItemKind::GlobalAsm(ref asm) => { + hir::ItemKind::GlobalAsm(asm) => { self.head("global_asm!"); self.print_inline_asm(asm); self.end() } - hir::ItemKind::TyAlias(ref ty, ref generics) => { - self.print_item_type(item, &generics, |state| { + hir::ItemKind::TyAlias(ty, generics) => { + self.print_item_type(item, generics, |state| { state.word_space("="); - state.print_type(&ty); + state.print_type(ty); }); } hir::ItemKind::OpaqueTy(ref opaque_ty) => { - self.print_item_type(item, &opaque_ty.generics, |state| { + self.print_item_type(item, opaque_ty.generics, |state| { let mut real_bounds = Vec::with_capacity(opaque_ty.bounds.len()); - for b in opaque_ty.bounds.iter() { - if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + for b in opaque_ty.bounds { + if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b { state.space(); state.word_space("for ?"); state.print_trait_ref(&ptr.trait_ref); @@ -604,39 +598,39 @@ impl<'a> State<'a> { state.print_bounds("= impl", real_bounds); }); } - hir::ItemKind::Enum(ref enum_definition, ref params) => { + hir::ItemKind::Enum(ref enum_definition, params) => { self.print_enum_def(enum_definition, params, item.ident.name, item.span); } - hir::ItemKind::Struct(ref struct_def, ref generics) => { + hir::ItemKind::Struct(ref struct_def, generics) => { self.head("struct"); self.print_struct(struct_def, generics, item.ident.name, item.span, true); } - hir::ItemKind::Union(ref struct_def, ref generics) => { + hir::ItemKind::Union(ref struct_def, generics) => { self.head("union"); self.print_struct(struct_def, generics, item.ident.name, item.span, true); } - hir::ItemKind::Impl(hir::Impl { + hir::ItemKind::Impl(&hir::Impl { unsafety, polarity, defaultness, constness, defaultness_span: _, - ref generics, + generics, ref of_trait, - ref self_ty, + self_ty, items, }) => { self.head(""); - self.print_defaultness(*defaultness); - self.print_unsafety(*unsafety); + self.print_defaultness(defaultness); + self.print_unsafety(unsafety); self.word_nbsp("impl"); if !generics.params.is_empty() { - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); self.space(); } - if *constness == hir::Constness::Const { + if constness == hir::Constness::Const { self.word_nbsp("const"); } @@ -644,33 +638,33 @@ impl<'a> State<'a> { self.word("!"); } - if let Some(ref t) = of_trait { + if let Some(t) = of_trait { self.print_trait_ref(t); self.space(); self.word_space("for"); } - self.print_type(&self_ty); + self.print_type(self_ty); self.print_where_clause(generics); self.space(); self.bopen(); self.print_inner_attributes(attrs); - for impl_item in *items { + for impl_item in items { self.ann.nested(self, Nested::ImplItem(impl_item.id)); } self.bclose(item.span); } - hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, trait_items) => { + hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, trait_items) => { self.head(""); self.print_is_auto(is_auto); self.print_unsafety(unsafety); self.word_nbsp("trait"); self.print_ident(item.ident); - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); let mut real_bounds = Vec::with_capacity(bounds.len()); - for b in bounds.iter() { - if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + for b in bounds { + if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b { self.space(); self.word_space("for ?"); self.print_trait_ref(&ptr.trait_ref); @@ -687,14 +681,14 @@ impl<'a> State<'a> { } self.bclose(item.span); } - hir::ItemKind::TraitAlias(ref generics, ref bounds) => { + hir::ItemKind::TraitAlias(generics, bounds) => { self.head("trait"); self.print_ident(item.ident); - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); let mut real_bounds = Vec::with_capacity(bounds.len()); // FIXME(durka) this seems to be some quite outdated syntax - for b in bounds.iter() { - if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + for b in bounds { + if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b { self.space(); self.word_space("for ?"); self.print_trait_ref(&ptr.trait_ref); @@ -714,7 +708,7 @@ impl<'a> State<'a> { } pub fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) { - self.print_path(&t.path, false) + self.print_path(t.path, false); } fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) { @@ -726,8 +720,8 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) { - self.print_formal_generic_params(&t.bound_generic_params); - self.print_trait_ref(&t.trait_ref) + self.print_formal_generic_params(t.bound_generic_params); + self.print_trait_ref(&t.trait_ref); } pub fn print_enum_def( @@ -739,10 +733,10 @@ impl<'a> State<'a> { ) { self.head("enum"); self.print_name(name); - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); self.print_where_clause(generics); self.space(); - self.print_variants(&enum_definition.variants, span) + self.print_variants(enum_definition.variants, span); } pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) { @@ -776,7 +770,7 @@ impl<'a> State<'a> { print_finalizer: bool, ) { self.print_name(name); - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); match struct_def { hir::VariantData::Tuple(..) | hir::VariantData::Unit(..) => { if let hir::VariantData::Tuple(..) = struct_def { @@ -784,7 +778,7 @@ impl<'a> State<'a> { self.commasep(Inconsistent, struct_def.fields(), |s, field| { s.maybe_print_comment(field.span.lo()); s.print_outer_attributes(s.attrs(field.hir_id)); - s.print_type(&field.ty) + s.print_type(field.ty); }); self.pclose(); } @@ -807,7 +801,7 @@ impl<'a> State<'a> { self.print_outer_attributes(self.attrs(field.hir_id)); self.print_ident(field.ident); self.word_nbsp(":"); - self.print_type(&field.ty); + self.print_type(field.ty); self.word(","); } @@ -819,7 +813,7 @@ impl<'a> State<'a> { pub fn print_variant(&mut self, v: &hir::Variant<'_>) { self.head(""); let generics = hir::Generics::empty(); - self.print_struct(&v.data, &generics, v.ident.name, v.span, false); + self.print_struct(&v.data, generics, v.ident.name, v.span, false); if let Some(ref d) = v.disr_expr { self.space(); self.word_space("="); @@ -834,7 +828,7 @@ impl<'a> State<'a> { arg_names: &[Ident], body_id: Option<hir::BodyId>, ) { - self.print_fn(&m.decl, m.header, Some(ident.name), generics, arg_names, body_id) + self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id); } pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { @@ -843,28 +837,23 @@ impl<'a> State<'a> { self.maybe_print_comment(ti.span.lo()); self.print_outer_attributes(self.attrs(ti.hir_id())); match ti.kind { - hir::TraitItemKind::Const(ref ty, default) => { - self.print_associated_const(ti.ident, &ty, default); + hir::TraitItemKind::Const(ty, default) => { + self.print_associated_const(ti.ident, ty, default); } - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref arg_names)) => { - self.print_method_sig(ti.ident, sig, &ti.generics, arg_names, None); + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_names)) => { + self.print_method_sig(ti.ident, sig, ti.generics, arg_names, None); self.word(";"); } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { self.head(""); - self.print_method_sig(ti.ident, sig, &ti.generics, &[], Some(body)); + self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(body)); self.nbsp(); self.end(); // need to close a box self.end(); // need to close a box self.ann.nested(self, Nested::Body(body)); } - hir::TraitItemKind::Type(ref bounds, ref default) => { - self.print_associated_type( - ti.ident, - &ti.generics, - Some(bounds), - default.as_ref().map(|ty| &**ty), - ); + hir::TraitItemKind::Type(bounds, default) => { + self.print_associated_type(ti.ident, ti.generics, Some(bounds), default); } } self.ann.post(self, AnnNode::SubItem(ti.hir_id())) @@ -877,25 +866,30 @@ impl<'a> State<'a> { self.print_outer_attributes(self.attrs(ii.hir_id())); match ii.kind { - hir::ImplItemKind::Const(ref ty, expr) => { - self.print_associated_const(ii.ident, &ty, Some(expr)); + hir::ImplItemKind::Const(ty, expr) => { + self.print_associated_const(ii.ident, ty, Some(expr)); } hir::ImplItemKind::Fn(ref sig, body) => { self.head(""); - self.print_method_sig(ii.ident, sig, &ii.generics, &[], Some(body)); + self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(body)); self.nbsp(); self.end(); // need to close a box self.end(); // need to close a box self.ann.nested(self, Nested::Body(body)); } - hir::ImplItemKind::TyAlias(ref ty) => { - self.print_associated_type(ii.ident, &ii.generics, None, Some(ty)); + hir::ImplItemKind::TyAlias(ty) => { + self.print_associated_type(ii.ident, ii.generics, None, Some(ty)); } } self.ann.post(self, AnnNode::SubItem(ii.hir_id())) } - pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) { + pub fn print_local( + &mut self, + init: Option<&hir::Expr<'_>>, + els: Option<&hir::Block<'_>>, + decl: impl Fn(&mut Self), + ) { self.space_if_not_bol(); self.ibox(INDENT_UNIT); self.word_nbsp("let"); @@ -904,28 +898,35 @@ impl<'a> State<'a> { decl(self); self.end(); - if let Some(ref init) = init { + if let Some(init) = init { self.nbsp(); self.word_space("="); - self.print_expr(&init); + self.print_expr(init); } + + if let Some(els) = els { + self.nbsp(); + self.word_space("else"); + self.print_block(els); + } + self.end() } pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) { self.maybe_print_comment(st.span.lo()); match st.kind { - hir::StmtKind::Local(ref loc) => { - self.print_local(loc.init, |this| this.print_local_decl(&loc)); + hir::StmtKind::Local(loc) => { + self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc)); } hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), - hir::StmtKind::Expr(ref expr) => { + hir::StmtKind::Expr(expr) => { self.space_if_not_bol(); - self.print_expr(&expr); + self.print_expr(expr); } - hir::StmtKind::Semi(ref expr) => { + hir::StmtKind::Semi(expr) => { self.space_if_not_bol(); - self.print_expr(&expr); + self.print_expr(expr); self.word(";"); } } @@ -966,9 +967,9 @@ impl<'a> State<'a> { for st in blk.stmts { self.print_stmt(st); } - if let Some(ref expr) = blk.expr { + if let Some(expr) = blk.expr { self.space_if_not_bol(); - self.print_expr(&expr); + self.print_expr(expr); self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi())); } self.bclose_maybe_open(blk.span, close_box); @@ -979,21 +980,21 @@ impl<'a> State<'a> { if let Some(els_inner) = els { match els_inner.kind { // Another `else if` block. - hir::ExprKind::If(ref i, ref then, ref e) => { + hir::ExprKind::If(i, then, e) => { self.cbox(INDENT_UNIT - 1); self.ibox(0); self.word(" else if "); - self.print_expr_as_cond(&i); + self.print_expr_as_cond(i); self.space(); - self.print_expr(&then); - self.print_else(e.as_ref().map(|e| &**e)) + self.print_expr(then); + self.print_else(e); } // Final `else` block. - hir::ExprKind::Block(ref b, _) => { + hir::ExprKind::Block(b, _) => { self.cbox(INDENT_UNIT - 1); self.ibox(0); self.word(" else "); - self.print_block(&b) + self.print_block(b); } // Constraints would be great here! _ => { @@ -1048,7 +1049,7 @@ impl<'a> State<'a> { if needs_par { self.popen(); } - if let hir::ExprKind::DropTemps(ref actual_expr) = expr.kind { + if let hir::ExprKind::DropTemps(actual_expr) = expr.kind { self.print_expr(actual_expr); } else { self.print_expr(expr); @@ -1114,7 +1115,7 @@ impl<'a> State<'a> { &mut self, qpath: &hir::QPath<'_>, fields: &[hir::ExprField<'_>], - wth: &Option<&hir::Expr<'_>>, + wth: Option<&hir::Expr<'_>>, ) { self.print_qpath(qpath, true); self.word("{"); @@ -1127,28 +1128,24 @@ impl<'a> State<'a> { s.print_ident(field.ident); s.word_space(":"); } - s.print_expr(&field.expr); + s.print_expr(field.expr); s.end() }, |f| f.span, ); - match *wth { - Some(ref expr) => { - self.ibox(INDENT_UNIT); - if !fields.is_empty() { - self.word(","); - self.space(); - } - self.word(".."); - self.print_expr(&expr); - self.end(); - } - _ => { - if !fields.is_empty() { - self.word(",") - } + if let Some(expr) = wth { + self.ibox(INDENT_UNIT); + if !fields.is_empty() { + self.word(","); + self.space(); } + self.word(".."); + self.print_expr(expr); + self.end(); + } else if !fields.is_empty() { + self.word(","); } + self.word("}"); } @@ -1249,18 +1246,17 @@ impl<'a> State<'a> { Options(ast::InlineAsmOptions), } - let mut args = - vec![AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&asm.template))]; + let mut args = vec![AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(asm.template))]; args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o))); if !asm.options.is_empty() { args.push(AsmArg::Options(asm.options)); } self.popen(); - self.commasep(Consistent, &args, |s, arg| match arg { - AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked), - AsmArg::Operand(op) => match op { - hir::InlineAsmOperand::In { reg, expr } => { + self.commasep(Consistent, &args, |s, arg| match *arg { + AsmArg::Template(ref template) => s.print_string(template, ast::StrStyle::Cooked), + AsmArg::Operand(op) => match *op { + hir::InlineAsmOperand::In { reg, ref expr } => { s.word("in"); s.popen(); s.word(format!("{}", reg)); @@ -1268,8 +1264,8 @@ impl<'a> State<'a> { s.space(); s.print_expr(expr); } - hir::InlineAsmOperand::Out { reg, late, expr } => { - s.word(if *late { "lateout" } else { "out" }); + hir::InlineAsmOperand::Out { reg, late, ref expr } => { + s.word(if late { "lateout" } else { "out" }); s.popen(); s.word(format!("{}", reg)); s.pclose(); @@ -1279,16 +1275,16 @@ impl<'a> State<'a> { None => s.word("_"), } } - hir::InlineAsmOperand::InOut { reg, late, expr } => { - s.word(if *late { "inlateout" } else { "inout" }); + hir::InlineAsmOperand::InOut { reg, late, ref expr } => { + s.word(if late { "inlateout" } else { "inout" }); s.popen(); s.word(format!("{}", reg)); s.pclose(); s.space(); s.print_expr(expr); } - hir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { - s.word(if *late { "inlateout" } else { "inout" }); + hir::InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => { + s.word(if late { "inlateout" } else { "inout" }); s.popen(); s.word(format!("{}", reg)); s.pclose(); @@ -1301,17 +1297,17 @@ impl<'a> State<'a> { None => s.word("_"), } } - hir::InlineAsmOperand::Const { anon_const } => { + hir::InlineAsmOperand::Const { ref anon_const } => { s.word("const"); s.space(); s.print_anon_const(anon_const); } - hir::InlineAsmOperand::SymFn { anon_const } => { + hir::InlineAsmOperand::SymFn { ref anon_const } => { s.word("sym_fn"); s.space(); s.print_anon_const(anon_const); } - hir::InlineAsmOperand::SymStatic { path, def_id: _ } => { + hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => { s.word("sym_static"); s.space(); s.print_qpath(path, true); @@ -1363,57 +1359,57 @@ impl<'a> State<'a> { self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); match expr.kind { - hir::ExprKind::Box(ref expr) => { + hir::ExprKind::Box(expr) => { self.word_space("box"); self.print_expr_maybe_paren(expr, parser::PREC_PREFIX); } - hir::ExprKind::Array(ref exprs) => { + hir::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); } hir::ExprKind::ConstBlock(ref anon_const) => { self.print_expr_anon_const(anon_const); } - hir::ExprKind::Repeat(ref element, ref count) => { - self.print_expr_repeat(&element, count); + hir::ExprKind::Repeat(element, ref count) => { + self.print_expr_repeat(element, count); } - hir::ExprKind::Struct(ref qpath, fields, ref wth) => { + hir::ExprKind::Struct(qpath, fields, wth) => { self.print_expr_struct(qpath, fields, wth); } - hir::ExprKind::Tup(ref exprs) => { + hir::ExprKind::Tup(exprs) => { self.print_expr_tup(exprs); } - hir::ExprKind::Call(ref func, ref args) => { - self.print_expr_call(&func, args); + hir::ExprKind::Call(func, args) => { + self.print_expr_call(func, args); } - hir::ExprKind::MethodCall(ref segment, ref args, _) => { + hir::ExprKind::MethodCall(segment, args, _) => { self.print_expr_method_call(segment, args); } - hir::ExprKind::Binary(op, ref lhs, ref rhs) => { - self.print_expr_binary(op, &lhs, &rhs); + hir::ExprKind::Binary(op, lhs, rhs) => { + self.print_expr_binary(op, lhs, rhs); } - hir::ExprKind::Unary(op, ref expr) => { - self.print_expr_unary(op, &expr); + hir::ExprKind::Unary(op, expr) => { + self.print_expr_unary(op, expr); } - hir::ExprKind::AddrOf(k, m, ref expr) => { - self.print_expr_addr_of(k, m, &expr); + hir::ExprKind::AddrOf(k, m, expr) => { + self.print_expr_addr_of(k, m, expr); } hir::ExprKind::Lit(ref lit) => { - self.print_literal(&lit); + self.print_literal(lit); } - hir::ExprKind::Cast(ref expr, ref ty) => { + hir::ExprKind::Cast(expr, ty) => { let prec = AssocOp::As.precedence() as i8; - self.print_expr_maybe_paren(&expr, prec); + self.print_expr_maybe_paren(expr, prec); self.space(); self.word_space("as"); - self.print_type(&ty); + self.print_type(ty); } - hir::ExprKind::Type(ref expr, ref ty) => { + hir::ExprKind::Type(expr, ty) => { let prec = AssocOp::Colon.precedence() as i8; - self.print_expr_maybe_paren(&expr, prec); + self.print_expr_maybe_paren(expr, prec); self.word_space(":"); - self.print_type(&ty); + self.print_type(ty); } - hir::ExprKind::DropTemps(ref init) => { + hir::ExprKind::DropTemps(init) => { // Print `{`: self.cbox(INDENT_UNIT); self.ibox(0); @@ -1421,7 +1417,7 @@ impl<'a> State<'a> { // Print `let _t = $init;`: let temp = Ident::from_str("_t"); - self.print_local(Some(init), |this| this.print_ident(temp)); + self.print_local(Some(init), None, |this| this.print_ident(temp)); self.word(";"); // Print `_t`: @@ -1431,25 +1427,25 @@ impl<'a> State<'a> { // Print `}`: self.bclose_maybe_open(expr.span, true); } - hir::ExprKind::Let(hir::Let { pat, ty, init, .. }) => { - self.print_let(pat, *ty, init); + hir::ExprKind::Let(&hir::Let { pat, ty, init, .. }) => { + self.print_let(pat, ty, init); } - hir::ExprKind::If(ref test, ref blk, ref elseopt) => { - self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e)); + hir::ExprKind::If(test, blk, elseopt) => { + self.print_if(test, blk, elseopt); } - hir::ExprKind::Loop(ref blk, opt_label, _, _) => { + hir::ExprKind::Loop(blk, opt_label, _, _) => { if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); } self.head("loop"); - self.print_block(&blk); + self.print_block(blk); } - hir::ExprKind::Match(ref expr, arms, _) => { + hir::ExprKind::Match(expr, arms, _) => { self.cbox(INDENT_UNIT); self.ibox(INDENT_UNIT); self.word_nbsp("match"); - self.print_expr_as_cond(&expr); + self.print_expr_as_cond(expr); self.space(); self.bopen(); for arm in arms { @@ -1457,18 +1453,19 @@ impl<'a> State<'a> { } self.bclose(expr.span); } - hir::ExprKind::Closure { + hir::ExprKind::Closure(&hir::Closure { + binder, capture_clause, bound_generic_params, - ref fn_decl, + fn_decl, body, fn_decl_span: _, movability: _, - } => { - self.print_formal_generic_params(bound_generic_params); + }) => { + self.print_closure_binder(binder, bound_generic_params); self.print_capture_clause(capture_clause); - self.print_closure_params(&fn_decl, body); + self.print_closure_params(fn_decl, body); self.space(); // This is a bare expression. @@ -1480,7 +1477,7 @@ impl<'a> State<'a> { // empty box to satisfy the close. self.ibox(0); } - hir::ExprKind::Block(ref blk, opt_label) => { + hir::ExprKind::Block(blk, opt_label) => { if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); @@ -1489,42 +1486,42 @@ impl<'a> State<'a> { self.cbox(INDENT_UNIT); // head-box, will be closed by print-block after `{` self.ibox(0); - self.print_block(&blk); + self.print_block(blk); } - hir::ExprKind::Assign(ref lhs, ref rhs, _) => { + hir::ExprKind::Assign(lhs, rhs, _) => { let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren(&lhs, prec + 1); + self.print_expr_maybe_paren(lhs, prec + 1); self.space(); self.word_space("="); - self.print_expr_maybe_paren(&rhs, prec); + self.print_expr_maybe_paren(rhs, prec); } - hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => { + hir::ExprKind::AssignOp(op, lhs, rhs) => { let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren(&lhs, prec + 1); + self.print_expr_maybe_paren(lhs, prec + 1); self.space(); self.word(op.node.as_str()); self.word_space("="); - self.print_expr_maybe_paren(&rhs, prec); + self.print_expr_maybe_paren(rhs, prec); } - hir::ExprKind::Field(ref expr, ident) => { + hir::ExprKind::Field(expr, ident) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); self.word("."); self.print_ident(ident); } - hir::ExprKind::Index(ref expr, ref index) => { - self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX); + hir::ExprKind::Index(expr, index) => { + self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); self.word("["); - self.print_expr(&index); + self.print_expr(index); self.word("]"); } hir::ExprKind::Path(ref qpath) => self.print_qpath(qpath, true), - hir::ExprKind::Break(destination, ref opt_expr) => { + hir::ExprKind::Break(destination, opt_expr) => { self.word("break"); if let Some(label) = destination.label { self.space(); self.print_ident(label.ident); } - if let Some(ref expr) = *opt_expr { + if let Some(expr) = opt_expr { self.space(); self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } @@ -1536,20 +1533,20 @@ impl<'a> State<'a> { self.print_ident(label.ident); } } - hir::ExprKind::Ret(ref result) => { + hir::ExprKind::Ret(result) => { self.word("return"); - if let Some(ref expr) = *result { + if let Some(expr) = result { self.word(" "); - self.print_expr_maybe_paren(&expr, parser::PREC_JUMP); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } } - hir::ExprKind::InlineAsm(ref asm) => { + hir::ExprKind::InlineAsm(asm) => { self.word("asm!"); self.print_inline_asm(asm); } - hir::ExprKind::Yield(ref expr, _) => { + hir::ExprKind::Yield(expr, _) => { self.word_space("yield"); - self.print_expr_maybe_paren(&expr, parser::PREC_JUMP); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } hir::ExprKind::Err => { self.popen(); @@ -1562,10 +1559,10 @@ impl<'a> State<'a> { } pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) { - self.print_pat(&loc.pat); - if let Some(ref ty) = loc.ty { + self.print_pat(loc.pat); + if let Some(ty) = loc.ty { self.word_space(":"); - self.print_type(&ty); + self.print_type(ty); } } @@ -1596,8 +1593,8 @@ impl<'a> State<'a> { pub fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) { match *qpath { - hir::QPath::Resolved(None, ref path) => self.print_path(path, colons_before_params), - hir::QPath::Resolved(Some(ref qself), ref path) => { + hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params), + hir::QPath::Resolved(Some(qself), path) => { self.word("<"); self.print_type(qself); self.space(); @@ -1627,11 +1624,11 @@ impl<'a> State<'a> { colons_before_params, ) } - hir::QPath::TypeRelative(ref qself, ref item_segment) => { + hir::QPath::TypeRelative(qself, item_segment) => { // If we've got a compound-qualified-path, let's push an additional pair of angle // brackets, so that we pretty-print `<<A::B>::C>` as `<A::B>::C`, instead of just // `A::B::C` (since the latter could be ambiguous to the user) - if let hir::TyKind::Path(hir::QPath::Resolved(None, _)) = &qself.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, _)) = qself.kind { self.print_type(qself); } else { self.word("<"); @@ -1663,7 +1660,7 @@ impl<'a> State<'a> { ) { if generic_args.parenthesized { self.word("("); - self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(&ty)); + self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(ty)); self.word(")"); self.space_if_not_bol(); @@ -1694,7 +1691,7 @@ impl<'a> State<'a> { start_or_comma(self); self.commasep( Inconsistent, - &generic_args.args, + generic_args.args, |s, generic_arg| match generic_arg { GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt), GenericArg::Lifetime(_) => {} @@ -1712,7 +1709,7 @@ impl<'a> State<'a> { self.word(".."); } - for binding in generic_args.bindings.iter() { + for binding in generic_args.bindings { start_or_comma(self); self.print_type_binding(binding); } @@ -1731,7 +1728,7 @@ impl<'a> State<'a> { hir::TypeBindingKind::Equality { ref term } => { self.word_space("="); match term { - Term::Ty(ref ty) => self.print_type(ty), + Term::Ty(ty) => self.print_type(ty), Term::Const(ref c) => self.print_anon_const(c), } } @@ -1748,7 +1745,7 @@ impl<'a> State<'a> { // is that it doesn't matter match pat.kind { PatKind::Wild => self.word("_"), - PatKind::Binding(binding_mode, _, ident, ref sub) => { + PatKind::Binding(binding_mode, _, ident, sub) => { match binding_mode { hir::BindingAnnotation::Ref => { self.word_nbsp("ref"); @@ -1764,33 +1761,33 @@ impl<'a> State<'a> { } } self.print_ident(ident); - if let Some(ref p) = *sub { + if let Some(p) = sub { self.word("@"); - self.print_pat(&p); + self.print_pat(p); } } - PatKind::TupleStruct(ref qpath, ref elts, ddpos) => { + PatKind::TupleStruct(ref qpath, elts, ddpos) => { self.print_qpath(qpath, true); self.popen(); if let Some(ddpos) = ddpos { - self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); } self.word(".."); if ddpos != elts.len() { self.word(","); - self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p)); } } else { - self.commasep(Inconsistent, &elts, |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); } self.pclose(); } PatKind::Path(ref qpath) => { self.print_qpath(qpath, true); } - PatKind::Struct(ref qpath, ref fields, etc) => { + PatKind::Struct(ref qpath, fields, etc) => { self.print_qpath(qpath, true); self.nbsp(); self.word("{"); @@ -1800,14 +1797,14 @@ impl<'a> State<'a> { } self.commasep_cmnt( Consistent, - &fields, + fields, |s, f| { s.cbox(INDENT_UNIT); if !f.is_shorthand { s.print_ident(f.ident); s.word_nbsp(":"); } - s.print_pat(&f.pat); + s.print_pat(f.pat); s.end() }, |f| f.pat.span, @@ -1823,58 +1820,58 @@ impl<'a> State<'a> { } self.word("}"); } - PatKind::Or(ref pats) => { - self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(&p)); + PatKind::Or(pats) => { + self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p)); } - PatKind::Tuple(ref elts, ddpos) => { + PatKind::Tuple(elts, ddpos) => { self.popen(); if let Some(ddpos) = ddpos { - self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); } self.word(".."); if ddpos != elts.len() { self.word(","); - self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p)); } } else { - self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, elts, |s, p| s.print_pat(p)); if elts.len() == 1 { self.word(","); } } self.pclose(); } - PatKind::Box(ref inner) => { + PatKind::Box(inner) => { let is_range_inner = matches!(inner.kind, PatKind::Range(..)); self.word("box "); if is_range_inner { self.popen(); } - self.print_pat(&inner); + self.print_pat(inner); if is_range_inner { self.pclose(); } } - PatKind::Ref(ref inner, mutbl) => { + PatKind::Ref(inner, mutbl) => { let is_range_inner = matches!(inner.kind, PatKind::Range(..)); self.word("&"); self.word(mutbl.prefix_str()); if is_range_inner { self.popen(); } - self.print_pat(&inner); + self.print_pat(inner); if is_range_inner { self.pclose(); } } - PatKind::Lit(ref e) => self.print_expr(&e), - PatKind::Range(ref begin, ref end, ref end_kind) => { + PatKind::Lit(e) => self.print_expr(e), + PatKind::Range(begin, end, end_kind) => { if let Some(expr) = begin { self.print_expr(expr); } - match *end_kind { + match end_kind { RangeEnd::Included => self.word("..."), RangeEnd::Excluded => self.word(".."), } @@ -1882,24 +1879,24 @@ impl<'a> State<'a> { self.print_expr(expr); } } - PatKind::Slice(ref before, ref slice, ref after) => { + PatKind::Slice(before, slice, after) => { self.word("["); - self.commasep(Inconsistent, &before, |s, p| s.print_pat(&p)); - if let Some(ref p) = *slice { + self.commasep(Inconsistent, before, |s, p| s.print_pat(p)); + if let Some(p) = slice { if !before.is_empty() { self.word_space(","); } if let PatKind::Wild = p.kind { // Print nothing. } else { - self.print_pat(&p); + self.print_pat(p); } self.word(".."); if !after.is_empty() { self.word_space(","); } } - self.commasep(Inconsistent, &after, |s, p| s.print_pat(&p)); + self.commasep(Inconsistent, after, |s, p| s.print_pat(p)); self.word("]"); } } @@ -1908,7 +1905,7 @@ impl<'a> State<'a> { pub fn print_param(&mut self, arg: &hir::Param<'_>) { self.print_outer_attributes(self.attrs(arg.hir_id)); - self.print_pat(&arg.pat); + self.print_pat(arg.pat); } pub fn print_arm(&mut self, arm: &hir::Arm<'_>) { @@ -1920,32 +1917,32 @@ impl<'a> State<'a> { self.cbox(INDENT_UNIT); self.ann.pre(self, AnnNode::Arm(arm)); self.ibox(0); - self.print_outer_attributes(&self.attrs(arm.hir_id)); - self.print_pat(&arm.pat); + self.print_outer_attributes(self.attrs(arm.hir_id)); + self.print_pat(arm.pat); self.space(); if let Some(ref g) = arm.guard { - match g { + match *g { hir::Guard::If(e) => { self.word_space("if"); - self.print_expr(&e); + self.print_expr(e); self.space(); } - hir::Guard::IfLet(hir::Let { pat, ty, init, .. }) => { + hir::Guard::IfLet(&hir::Let { pat, ty, init, .. }) => { self.word_nbsp("if"); - self.print_let(pat, *ty, init); + self.print_let(pat, ty, init); } } } self.word_space("=>"); match arm.body.kind { - hir::ExprKind::Block(ref blk, opt_label) => { + hir::ExprKind::Block(blk, opt_label) => { if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); } // the block will close the pattern's ibox - self.print_block_unclosed(&blk); + self.print_block_unclosed(blk); // If it is a user-provided unsafe block, print a comma after it if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = blk.rules @@ -1955,7 +1952,7 @@ impl<'a> State<'a> { } _ => { self.end(); // close the ibox for the pattern - self.print_expr(&arm.body); + self.print_expr(arm.body); self.word(","); } } @@ -1978,13 +1975,13 @@ impl<'a> State<'a> { self.nbsp(); self.print_name(name); } - self.print_generic_params(&generics.params); + self.print_generic_params(generics.params); self.popen(); let mut i = 0; // Make sure we aren't supplied *both* `arg_names` and `body_id`. assert!(arg_names.is_empty() || body_id.is_none()); - self.commasep(Inconsistent, &decl.inputs, |s, ty| { + self.commasep(Inconsistent, decl.inputs, |s, ty| { s.ibox(INDENT_UNIT); if let Some(arg_name) = arg_names.get(i) { s.word(arg_name.to_string()); @@ -2011,7 +2008,7 @@ impl<'a> State<'a> { fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) { self.word("|"); let mut i = 0; - self.commasep(Inconsistent, &decl.inputs, |s, ty| { + self.commasep(Inconsistent, decl.inputs, |s, ty| { s.ibox(INDENT_UNIT); s.ann.nested(s, Nested::BodyParamPat(body_id, i)); @@ -2035,8 +2032,8 @@ impl<'a> State<'a> { self.space_if_not_bol(); self.word_space("->"); match decl.output { - hir::FnRetTy::Return(ref ty) => { - self.print_type(&ty); + hir::FnRetTy::Return(ty) => { + self.print_type(ty); self.maybe_print_comment(ty.span.lo()); } hir::FnRetTy::DefaultReturn(..) => unreachable!(), @@ -2050,6 +2047,42 @@ impl<'a> State<'a> { } } + pub fn print_closure_binder( + &mut self, + binder: hir::ClosureBinder, + generic_params: &[GenericParam<'_>], + ) { + let generic_params = generic_params + .iter() + .filter(|p| { + matches!( + p, + GenericParam { + kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit }, + .. + } + ) + }) + .collect::<Vec<_>>(); + + match binder { + hir::ClosureBinder::Default => {} + // we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions + hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"), + hir::ClosureBinder::For { .. } => { + self.word("for"); + self.word("<"); + + self.commasep(Inconsistent, &generic_params, |s, param| { + s.print_generic_param(param) + }); + + self.word(">"); + self.nbsp(); + } + } + } + pub fn print_bounds<'b>( &mut self, prefix: &'static str, @@ -2107,20 +2140,20 @@ impl<'a> State<'a> { match param.kind { GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { ref default, .. } => { + GenericParamKind::Type { default, .. } => { if let Some(default) = default { self.space(); self.word_space("="); - self.print_type(&default) + self.print_type(default); } } - GenericParamKind::Const { ref ty, ref default } => { + GenericParamKind::Const { ty, ref default } => { self.word_space(":"); self.print_type(ty); - if let Some(ref default) = default { + if let Some(default) = default { self.space(); self.word_space("="); - self.print_anon_const(&default) + self.print_anon_const(default); } } } @@ -2143,7 +2176,7 @@ impl<'a> State<'a> { self.word_space(","); } - match predicate { + match *predicate { hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params, bounded_ty, @@ -2151,11 +2184,11 @@ impl<'a> State<'a> { .. }) => { self.print_formal_generic_params(bound_generic_params); - self.print_type(&bounded_ty); - self.print_bounds(":", *bounds); + self.print_type(bounded_ty); + self.print_bounds(":", bounds); } hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - lifetime, + ref lifetime, bounds, .. }) => { @@ -2200,7 +2233,7 @@ impl<'a> State<'a> { pub fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) { self.print_mutability(mt.mutbl, print_const); - self.print_type(&mt.ty) + self.print_type(mt.ty); } pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) { @@ -2213,11 +2246,11 @@ impl<'a> State<'a> { self.word_space("->"); match decl.output { hir::FnRetTy::DefaultReturn(..) => unreachable!(), - hir::FnRetTy::Return(ref ty) => self.print_type(&ty), + hir::FnRetTy::Return(ty) => self.print_type(ty), } self.end(); - if let hir::FnRetTy::Return(ref output) = decl.output { + if let hir::FnRetTy::Return(output) = decl.output { self.maybe_print_comment(output.span.lo()); } } @@ -2243,7 +2276,7 @@ impl<'a> State<'a> { asyncness: hir::IsAsync::NotAsync, }, name, - &generics, + generics, arg_names, None, ); @@ -2312,7 +2345,7 @@ fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool { match *stmt { hir::StmtKind::Local(_) => true, hir::StmtKind::Item(_) => false, - hir::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(&e), + hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e), hir::StmtKind::Semi(..) => false, } } @@ -2351,22 +2384,22 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool { match value.kind { hir::ExprKind::Struct(..) => true, - hir::ExprKind::Assign(ref lhs, ref rhs, _) - | hir::ExprKind::AssignOp(_, ref lhs, ref rhs) - | hir::ExprKind::Binary(_, ref lhs, ref rhs) => { + hir::ExprKind::Assign(lhs, rhs, _) + | hir::ExprKind::AssignOp(_, lhs, rhs) + | hir::ExprKind::Binary(_, lhs, rhs) => { // `X { y: 1 } + X { y: 2 }` - contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) + contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs) } - hir::ExprKind::Unary(_, ref x) - | hir::ExprKind::Cast(ref x, _) - | hir::ExprKind::Type(ref x, _) - | hir::ExprKind::Field(ref x, _) - | hir::ExprKind::Index(ref x, _) => { + hir::ExprKind::Unary(_, x) + | hir::ExprKind::Cast(x, _) + | hir::ExprKind::Type(x, _) + | hir::ExprKind::Field(x, _) + | hir::ExprKind::Index(x, _) => { // `&X { y: 1 }, X { y: 1 }.y` - contains_exterior_struct_lit(&x) + contains_exterior_struct_lit(x) } - hir::ExprKind::MethodCall(.., ref exprs, _) => { + hir::ExprKind::MethodCall(.., exprs, _) => { // `X { y: 1 }.bar(...)` contains_exterior_struct_lit(&exprs[0]) } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index a89b9eafaa62d..69e482ce854c0 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -55,11 +55,11 @@ use std::io::{BufWriter, Write}; #[allow(missing_docs)] pub fn assert_dep_graph(tcx: TyCtxt<'_>) { tcx.dep_graph.with_ignore(|| { - if tcx.sess.opts.debugging_opts.dump_dep_graph { + if tcx.sess.opts.unstable_opts.dump_dep_graph { tcx.dep_graph.with_query(dump_graph); } - if !tcx.sess.opts.debugging_opts.query_dep_graph { + if !tcx.sess.opts.unstable_opts.query_dep_graph { return; } @@ -75,13 +75,13 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(hir::CRATE_HIR_ID); - tcx.hir().deep_visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes_in_crate(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; if !if_this_changed.is_empty() || !then_this_would_need.is_empty() { assert!( - tcx.sess.opts.debugging_opts.query_dep_graph, + tcx.sess.opts.unstable_opts.query_dep_graph, "cannot use the `#[{}]` or `#[{}]` annotations \ without supplying `-Z query-dep-graph`", sym::rustc_if_this_changed, diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 61b1dd8cb017c..00aefac645f18 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -76,7 +76,7 @@ impl<'tcx> AssertModuleSource<'tcx> { return; }; - if !self.tcx.sess.opts.debugging_opts.query_dep_graph { + if !self.tcx.sess.opts.unstable_opts.query_dep_graph { self.tcx.sess.span_fatal( attr.span, "found CGU-reuse attribute but `-Zquery-dep-graph` was not specified", diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 94097357f8c10..35a278e6c92ab 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -134,7 +134,7 @@ struct Assertion { } pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { - if !tcx.sess.opts.debugging_opts.query_dep_graph { + if !tcx.sess.opts.unstable_opts.query_dep_graph { return; } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 9b32884205650..25c1b2e1c4387 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -447,7 +447,7 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo } } - if sess.opts.debugging_opts.incremental_info { + if sess.opts.unstable_opts.incremental_info { eprintln!( "[incremental] session directory: \ {} files hard-linked", diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 9c325faae8058..1c5fd91690230 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -141,7 +141,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`. // Fortunately, we just checked that this isn't the case. let path = dep_graph_path(&sess); - let report_incremental_info = sess.opts.debugging_opts.incremental_info; + let report_incremental_info = sess.opts.unstable_opts.incremental_info; let expected_hash = sess.opts.dep_tracking_hash(false); let mut prev_work_products = FxHashMap::default(); @@ -161,19 +161,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { Decodable::decode(&mut work_product_decoder); for swp in work_products { - let mut all_files_exist = true; - let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file); - if !path.exists() { - all_files_exist = false; - - if sess.opts.debugging_opts.incremental_info { - eprintln!( - "incremental: could not find file for work \ - product: {}", - path.display() - ); + let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| { + let exists = in_incr_comp_dir_sess(sess, path).exists(); + if !exists && sess.opts.unstable_opts.incremental_info { + eprintln!("incremental: could not find file for work product: {path}",); } - } + exists + }); if all_files_exist { debug!("reconcile_work_products: all files for {:?} exist", swp); @@ -231,7 +225,7 @@ pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Opt let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); match load_data( - sess.opts.debugging_opts.incremental_info, + sess.opts.unstable_opts.incremental_info, &query_cache_path(sess), sess.is_nightly_build(), ) { diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 79836d66011a2..710350314975c 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -39,7 +39,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx)); sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx)); - if sess.opts.debugging_opts.incremental_info { + if sess.opts.unstable_opts.incremental_info { tcx.dep_graph.print_incremental_info() } @@ -108,16 +108,17 @@ pub fn save_work_product_index( for (id, wp) in previous_work_products.iter() { if !new_work_products.contains_key(id) { work_product::delete_workproduct_files(sess, wp); - debug_assert!(!in_incr_comp_dir_sess(sess, &wp.saved_file).exists()); + debug_assert!( + !wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists()) + ); } } // Check that we did not delete one of the current work-products: debug_assert!({ - new_work_products - .iter() - .map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file)) - .all(|path| path.exists()) + new_work_products.iter().all(|(_, wp)| { + wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists()) + }) }); } @@ -181,7 +182,7 @@ pub fn build_dep_graph( prev_graph, prev_work_products, encoder, - sess.opts.debugging_opts.query_dep_graph, - sess.opts.debugging_opts.incremental_info, + sess.opts.unstable_opts.query_dep_graph, + sess.opts.unstable_opts.incremental_info, )) } diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index 4789c0f581fdb..1b184eca964c3 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -3,6 +3,7 @@ //! [work products]: WorkProduct use crate::persist::fs::*; +use rustc_data_structures::stable_map::FxHashMap; use rustc_fs_util::link_or_copy; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -13,38 +14,41 @@ use std::path::Path; pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( sess: &Session, cgu_name: &str, - path: &Path, + files: &[(&'static str, &Path)], ) -> Option<(WorkProductId, WorkProduct)> { - debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path); + debug!(?cgu_name, ?files); sess.opts.incremental.as_ref()?; - let file_name = format!("{}.o", cgu_name); - let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); - let saved_file = match link_or_copy(path, &path_in_incr_dir) { - Ok(_) => file_name, - Err(err) => { - sess.warn(&format!( - "error copying object file `{}` to incremental directory as `{}`: {}", - path.display(), - path_in_incr_dir.display(), - err - )); - return None; + let mut saved_files = FxHashMap::default(); + for (ext, path) in files { + let file_name = format!("{cgu_name}.{ext}"); + let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); + match link_or_copy(path, &path_in_incr_dir) { + Ok(_) => { + let _ = saved_files.insert(ext.to_string(), file_name); + } + Err(err) => { + sess.warn(&format!( + "error copying object file `{}` to incremental directory as `{}`: {}", + path.display(), + path_in_incr_dir.display(), + err + )); + } } - }; - - let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file }; + } + let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files }; + debug!(?work_product); let work_product_id = WorkProductId::from_cgu_name(cgu_name); Some((work_product_id, work_product)) } /// Removes files for a given work product. pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) { - let path = in_incr_comp_dir_sess(sess, &work_product.saved_file); - match std_fs::remove_file(&path) { - Ok(()) => {} - Err(err) => { + for (_, path) in &work_product.saved_files { + let path = in_incr_comp_dir_sess(sess, path); + if let Err(err) = std_fs::remove_file(&path) { sess.warn(&format!( "file-system error deleting outdated file `{}`: {}", path.display(), diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 89419bfce6f5b..8a81a93a99cfd 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -10,4 +10,4 @@ doctest = false arrayvec = { version = "0.7", default-features = false } rustc_serialize = { path = "../rustc_serialize" } rustc_macros = { path = "../rustc_macros" } -smallvec = "1" +smallvec = "1.8.1" diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 976874c7cee83..5b664e19c18c0 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1546,6 +1546,16 @@ impl<T: Idx> GrowableBitSet<T> { let (word_index, mask) = word_index_and_mask(elem); self.bit_set.words.get(word_index).map_or(false, |word| (word & mask) != 0) } + + #[inline] + pub fn iter(&self) -> BitIter<'_, T> { + self.bit_set.iter() + } + + #[inline] + pub fn len(&self) -> usize { + self.bit_set.count() + } } impl<T: Idx> From<BitSet<T>> for GrowableBitSet<T> { diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index bbc2b76773471..02ac83a5e8b25 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -17,4 +17,4 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 8938ed78a94d7..1e8b212276f2f 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -128,7 +128,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let region_constraints = self.with_region_constraints(|region_constraints| { make_query_region_constraints( tcx, - region_obligations.iter().map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)), + region_obligations.iter().map(|r_o| (r_o.sup_type, r_o.sub_region)), region_constraints, ) }); @@ -714,10 +714,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { } fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) { - span_bug!( - self.cause.span(self.infcx.tcx), - "generic_const_exprs: unreachable `const_equate`" - ); + span_bug!(self.cause.span(), "generic_const_exprs: unreachable `const_equate`"); } fn normalization() -> NormalizationStrategy { diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 67dcb6e708b0e..8bf1de34a9b5c 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -37,7 +37,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b94d205488d01..d7505717bf3d2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -63,12 +63,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{Item, ItemKind, Node}; +use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, }; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; @@ -148,12 +148,10 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( tcx: TyCtxt<'tcx>, region: ty::Region<'tcx>, ) -> (String, Span) { - let sm = tcx.sess.source_map(); - let scope = region.free_region_binding_scope(tcx).expect_local(); match *region { ty::ReEarlyBound(ref br) => { - let mut sp = sm.guess_head_span(tcx.def_span(scope)); + let mut sp = tcx.def_span(scope); if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) { @@ -174,7 +172,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( } else { match fr.bound_region { ty::BoundRegionKind::BrNamed(_, name) => { - let mut sp = sm.guess_head_span(tcx.def_span(scope)); + let mut sp = tcx.def_span(scope); if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) { @@ -193,7 +191,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( ), _ => ( format!("the lifetime `{}` as defined here", region), - sm.guess_head_span(tcx.def_span(scope)), + tcx.def_span(scope), ), } } @@ -342,15 +340,19 @@ pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { ) | (&ty::Infer(ty::InferTy::TyVar(_)), _) | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true, - (&ty::Ref(reg_a, ty_a, mut_a), &ty::Ref(reg_b, ty_b, mut_b)) => { - reg_a == reg_b && mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b) + (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => { + mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b) } _ => a == b, } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_region_errors(&self, errors: &[RegionResolutionError<'tcx>]) { + pub fn report_region_errors( + &self, + generic_param_scope: LocalDefId, + errors: &[RegionResolutionError<'tcx>], + ) { debug!("report_region_errors(): {} errors to start", errors.len()); // try to pre-process the errors, which will group some of them @@ -381,6 +383,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { self.report_generic_bound_failure( + generic_param_scope, origin.span(), Some(origin), param_ty, @@ -1437,7 +1440,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { swap_secondary_and_primary: bool, force_label: bool, ) { - let span = cause.span(self.tcx); + let span = cause.span(); // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. @@ -1540,7 +1543,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) { let span = self.tcx.def_span(def_id); @@ -2087,7 +2090,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); - let span = trace.cause.span(self.tcx); + let span = trace.cause.span(); let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { FailureCode::Error0038(did) => { @@ -2271,56 +2274,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_generic_bound_failure( &self, + generic_param_scope: LocalDefId, span: Span, origin: Option<SubregionOrigin<'tcx>>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, ) { - let owner = - self.in_progress_typeck_results.map(|typeck_results| typeck_results.borrow().hir_owner); - self.construct_generic_bound_failure(span, origin, bound_kind, sub, owner).emit(); + self.construct_generic_bound_failure(generic_param_scope, span, origin, bound_kind, sub) + .emit(); } pub fn construct_generic_bound_failure( &self, + generic_param_scope: LocalDefId, span: Span, origin: Option<SubregionOrigin<'tcx>>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, - owner: Option<LocalDefId>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let hir = self.tcx.hir(); // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. - let generics = owner.map(|owner| { - let hir_id = hir.local_def_id_to_hir_id(owner); - let parent_id = hir.get_parent_item(hir_id); - ( - // Parent item could be a `mod`, so we check the HIR before calling: - if let Some(Node::Item(Item { - kind: ItemKind::Trait(..) | ItemKind::Impl { .. }, - .. - })) = hir.find_by_def_id(parent_id) - { - Some(self.tcx.generics_of(parent_id)) - } else { - None - }, - self.tcx.generics_of(owner.to_def_id()), - hir.span(hir_id), - ) - }); - - let span = match generics { - // This is to get around the trait identity obligation, that has a `DUMMY_SP` as signal - // for other diagnostics, so we need to recover it here. - Some((_, _, node)) if span.is_dummy() => node, - _ => span, - }; - + let generics = self.tcx.generics_of(generic_param_scope); // type_param_span is (span, has_bounds) - let type_param_span = match (generics, bound_kind) { - (Some((_, ref generics, _)), GenericKind::Param(ref param)) => { + let type_param_span = match bound_kind { + GenericKind::Param(ref param) => { // Account for the case where `param` corresponds to `Self`, // which doesn't have the expected type argument. if !(generics.has_self && param.index == 0) { @@ -2348,30 +2325,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => None, }; - let new_lt = generics - .as_ref() - .and_then(|(parent_g, g, _)| { - let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char)); - let mut lts_names = g - .params - .iter() + + let new_lt = { + let mut possible = (b'a'..=b'z').map(|c| format!("'{}", c as char)); + let lts_names = + iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p))) + .flat_map(|g| &g.params) .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) .map(|p| p.name.as_str()) .collect::<Vec<_>>(); - if let Some(g) = parent_g { - lts_names.extend( - g.params - .iter() - .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) - .map(|p| p.name.as_str()), - ); - } - possible.find(|candidate| !lts_names.contains(&&candidate[..])) - }) - .unwrap_or("'lt".to_string()); + possible + .find(|candidate| !lts_names.contains(&&candidate[..])) + .unwrap_or("'lt".to_string()) + }; + let add_lt_sugg = generics - .as_ref() - .and_then(|(_, g, _)| g.params.first()) + .params + .first() .and_then(|param| param.def_id.as_local()) .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt))); @@ -2573,7 +2543,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); if let Some(infer::RelateParamBound(_, t, _)) = origin { let return_impl_trait = - owner.and_then(|owner| self.tcx.return_type_impl_trait(owner)).is_some(); + self.tcx.return_type_impl_trait(generic_param_scope).is_some(); let t = self.resolve_vars_if_possible(t); match t.kind() { // We've got: diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 20b9ed9cd7356..b267140daa971 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -6,7 +6,7 @@ use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; +use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -138,7 +138,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind { - Some(name.to_string()) + Some(name) } else { None } @@ -151,7 +151,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind { - return Some(name.to_string()); + return Some(name); } else { None } @@ -313,11 +313,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn emit_inference_failure_err( &self, body_id: Option<hir::BodyId>, - span: Span, + failure_span: Span, arg: GenericArg<'tcx>, - // FIXME(#94483): Either use this or remove it. - _impl_candidates: Vec<ty::TraitRef<'tcx>>, error_code: TypeAnnotationNeeded, + should_label_span: bool, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); @@ -326,7 +325,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If we don't have any typeck results we're outside // of a body, so we won't be able to get better info // here. - return self.bad_inference_failure_err(span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let typeck_results = typeck_results.borrow(); let typeck_results = &typeck_results; @@ -334,12 +333,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg); if let Some(body_id) = body_id { let expr = self.tcx.hir().expect_expr(body_id.hir_id); - debug!(?expr); local_visitor.visit_expr(expr); } let Some(InferSource { span, kind }) = local_visitor.infer_source else { - return self.bad_inference_failure_err(span, arg_data, error_code) + return self.bad_inference_failure_err(failure_span, arg_data, error_code) }; let error_code = error_code.into(); @@ -348,6 +346,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &format!("type annotations needed{}", kind.ty_msg(self)), error_code, ); + + if should_label_span && !failure_span.overlaps(span) { + err.span_label(failure_span, "type must be known at this point"); + } + match kind { InferSourceKind::LetBinding { insert_span, pattern_name, ty } => { let suggestion_msg = if let Some(name) = pattern_name { @@ -529,6 +532,23 @@ enum InferSourceKind<'tcx> { }, } +impl<'tcx> InferSource<'tcx> { + fn from_expansion(&self) -> bool { + let source_from_expansion = match self.kind { + InferSourceKind::LetBinding { insert_span, .. } + | InferSourceKind::ClosureArg { insert_span, .. } + | InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(), + InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => { + receiver.span.from_expansion() + } + InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => { + data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion) + } + }; + source_from_expansion || self.span.from_expansion() + } +} + impl<'tcx> InferSourceKind<'tcx> { fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String { match *self { @@ -550,6 +570,7 @@ impl<'tcx> InferSourceKind<'tcx> { } } +#[derive(Debug)] struct InsertableGenericArgs<'tcx> { insert_span: Span, substs: SubstsRef<'tcx>, @@ -598,43 +619,65 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { /// Sources with a small cost are prefer and should result /// in a clearer and idiomatic suggestion. fn source_cost(&self, source: &InferSource<'tcx>) -> usize { - let tcx = self.infcx.tcx; - - fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize { - match arg.unpack() { - GenericArgKind::Lifetime(_) => 0, // erased - GenericArgKind::Type(ty) => ty_cost(ty), - GenericArgKind::Const(_) => 3, // some non-zero value - } + #[derive(Clone, Copy)] + struct CostCtxt<'tcx> { + tcx: TyCtxt<'tcx>, } - fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize { - match ty.kind() { - ty::Closure(..) => 100, - ty::FnDef(..) => 20, - ty::FnPtr(..) => 10, - ty::Infer(..) => 0, - _ => 1, + impl<'tcx> CostCtxt<'tcx> { + fn arg_cost(self, arg: GenericArg<'tcx>) -> usize { + match arg.unpack() { + GenericArgKind::Lifetime(_) => 0, // erased + GenericArgKind::Type(ty) => self.ty_cost(ty), + GenericArgKind::Const(_) => 3, // some non-zero value + } + } + fn ty_cost(self, ty: Ty<'tcx>) -> usize { + match *ty.kind() { + ty::Closure(..) => 1000, + ty::FnDef(..) => 150, + ty::FnPtr(..) => 30, + ty::Adt(def, substs) => { + 5 + self + .tcx + .generics_of(def.did()) + .own_substs_no_defaults(self.tcx, substs) + .iter() + .map(|&arg| self.arg_cost(arg)) + .sum::<usize>() + } + ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(), + ty::Ref(_, ty, _) => 2 + self.ty_cost(ty), + ty::Infer(..) => 0, + _ => 1, + } } } // The sources are listed in order of preference here. - match source.kind { - InferSourceKind::LetBinding { ty, .. } => ty_cost(ty), - InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty), + let tcx = self.infcx.tcx; + let ctx = CostCtxt { tcx }; + let base_cost = match source.kind { + InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty), + InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty), InferSourceKind::GenericArg { def_id, generic_args, .. } => { let variant_cost = match tcx.def_kind(def_id) { - DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly. - _ => 12, + // `None::<u32>` and friends are ugly. + DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, + _ => 10, }; - variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>() + variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>() } InferSourceKind::FullyQualifiedMethodCall { substs, .. } => { - 20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>() + 20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>() } InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => { - 30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 } + 30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 } } - } + }; + + let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 }; + + base_cost + suggestion_may_apply } /// Uses `fn source_cost` to determine whether this inference source is preferable to @@ -642,6 +685,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn update_infer_source(&mut self, new_source: InferSource<'tcx>) { let cost = self.source_cost(&new_source) + self.attempt; + debug!(?cost); self.attempt += 1; if cost < self.infer_source_cost { self.infer_source_cost = cost; @@ -649,6 +693,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } + fn node_substs_opt(&self, hir_id: HirId) -> Option<SubstsRef<'tcx>> { + let substs = self.typeck_results.node_substs_opt(hir_id); + self.infcx.resolve_vars_if_possible(substs) + } + fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> { let ty = self.typeck_results.node_type_opt(hir_id); self.infcx.resolve_vars_if_possible(ty) @@ -731,14 +780,24 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { let tcx = self.infcx.tcx; match expr.kind { hir::ExprKind::Path(ref path) => { - if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) { + if let Some(substs) = self.node_substs_opt(expr.hir_id) { return self.path_inferred_subst_iter(expr.hir_id, substs, path); } } - hir::ExprKind::Struct(path, _, _) => { + // FIXME(#98711): Ideally we would also deal with type relative + // paths here, even if that is quite rare. + // + // See the `need_type_info/expr-struct-type-relative-gat.rs` test + // for an example where that would be needed. + // + // However, the `type_dependent_def_id` for `Self::Output` in an + // impl is currently the `DefId` of `Output` in the trait definition + // which makes this somewhat difficult and prevents us from just + // using `self.path_inferred_subst_iter` here. + hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) => { if let Some(ty) = self.opt_node_type(expr.hir_id) { if let ty::Adt(_, substs) = ty.kind() { - return self.path_inferred_subst_iter(expr.hir_id, substs, path); + return Box::new(self.resolved_path_inferred_subst_iter(path, substs)); } } } @@ -749,7 +808,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { if generics.has_impl_trait() { None? } - let substs = self.typeck_results.node_substs_opt(expr.hir_id)?; + let substs = self.node_substs_opt(expr.hir_id)?; let span = tcx.hir().span(segment.hir_id?); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); InsertableGenericArgs { @@ -945,6 +1004,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { intravisit::walk_body(self, body); } + #[instrument(level = "debug", skip(self))] fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { let tcx = self.infcx.tcx; match expr.kind { @@ -959,12 +1019,14 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { _ => intravisit::walk_expr(self, expr), } - for InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } in - self.expr_inferred_subst_iter(expr) - { + for args in self.expr_inferred_subst_iter(expr) { + debug!(?args); + let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args; let generics = tcx.generics_of(generics_def_id); - if let Some(argument_index) = - generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg)) + if let Some(argument_index) = generics + .own_substs(substs) + .iter() + .position(|&arg| self.generic_arg_contains_target(arg)) { let substs = self.infcx.resolve_vars_if_possible(substs); let generic_args = &generics.own_substs_no_defaults(tcx, substs) @@ -989,7 +1051,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { if let Some(node_ty) = self.opt_node_type(expr.hir_id) { if let ( - &ExprKind::Closure { fn_decl, body, fn_decl_span, .. }, + &ExprKind::Closure(&Closure { fn_decl, body, fn_decl_span, .. }), ty::Closure(_, substs), ) = (&expr.kind, node_ty.kind()) { @@ -1020,7 +1082,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { .any(|generics| generics.has_impl_trait()) }; if let ExprKind::MethodCall(path, args, span) = expr.kind - && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) + && let Some(substs) = self.node_substs_opt(expr.hir_id) && substs.iter().any(|arg| self.generic_arg_contains_target(arg)) && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) && self.infcx.tcx.trait_of_item(def_id).is_some() diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index e2185d8613379..998699158ff48 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -204,7 +204,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { expected_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let span = cause.span(self.tcx()); + let span = cause.span(); let msg = format!( "implementation of `{}` is not general enough", self.tcx().def_path_str(trait_def_id), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 6935ce9710b6e..02928c4aa57cd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -10,7 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; use rustc_middle::ty::{ - self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor, + self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -194,10 +194,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if !v.0.is_empty() { span = v.0.clone().into(); for sp in v.0 { - span.push_span_label( - sp, - "`'static` requirement introduced here".to_string(), - ); + span.push_span_label(sp, "`'static` requirement introduced here"); } add_label = false; } @@ -205,13 +202,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if add_label { span.push_span_label( fn_decl.output.span(), - "requirement introduced by this return type".to_string(), + "requirement introduced by this return type", ); } - span.push_span_label( - cause.span, - "because of this returned expression".to_string(), - ); + span.push_span_label(cause.span, "because of this returned expression"); err.span_note( span, "`'static` lifetime requirement introduced by the return type", @@ -523,13 +517,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { hir_v.visit_ty(&self_ty); for span in &traits { let mut multi_span: MultiSpan = vec![*span].into(); - multi_span.push_span_label( - *span, - "this has an implicit `'static` lifetime requirement".to_string(), - ); + multi_span + .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); multi_span.push_span_label( ident.span, - "calling this method introduces the `impl`'s 'static` requirement".to_string(), + "calling this method introduces the `impl`'s 'static` requirement", ); err.span_note(multi_span, "the used `impl` has a `'static` requirement"); err.span_suggestion_verbose( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 17d4bb1bcbe35..91bf9695dfc14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::ty::print::RegionHighlightMode; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::{Span, Symbol}; use std::ops::ControlFlow; @@ -88,7 +88,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for HighlightBuilder<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if !r.has_name() && self.counter <= 3 { self.highlight.highlighting_region(r, self.counter); @@ -128,10 +128,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } let mut type_param_span: MultiSpan = visitor.types.to_vec().into(); for &span in &visitor.types { - type_param_span.push_span_label( - span, - "consider borrowing this type parameter in the trait".to_string(), - ); + type_param_span + .push_span_label(span, "consider borrowing this type parameter in the trait"); } err.note(&format!("expected `{}`\n found `{}`", expected, found)); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index b9596cd10ed97..b356da0be554e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeVisitable}; use rustc_span::Span; /// Information about the anonymous region we are searching for. @@ -79,7 +79,7 @@ pub fn find_param_with_region<'tcx>( // May return None; sometimes the tables are not yet populated. let ty = fn_sig.inputs()[index]; let mut found_anon_region = false; - let new_param_ty = tcx.fold_regions(ty, &mut false, |r, _| { + let new_param_ty = tcx.fold_regions(ty, |r, _| { if r == anon_region { found_anon_region = true; replace_region @@ -142,7 +142,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn includes_region( &self, - ty: Binder<'tcx, impl TypeFoldable<'tcx>>, + ty: Binder<'tcx, impl TypeVisitable<'tcx>>, region: ty::BoundRegionKind, ) -> bool { let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty); diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 082eb1bf11101..d566634a49203 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -4,8 +4,7 @@ //! and use that to decide when one free region outlives another, and so forth. use rustc_data_structures::transitive_relation::TransitiveRelation; -use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, Lift, Region, TyCtxt}; +use rustc_middle::ty::{Lift, Region, TyCtxt}; /// Combines a `FreeRegionMap` and a `TyCtxt`. /// @@ -14,16 +13,13 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt}; pub(crate) struct RegionRelations<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, - /// The context used for debug messages - pub context: DefId, - /// Free-region relationships. pub free_regions: &'a FreeRegionMap<'tcx>, } impl<'a, 'tcx> RegionRelations<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, context: DefId, free_regions: &'a FreeRegionMap<'tcx>) -> Self { - Self { tcx, context, free_regions } + pub fn new(tcx: TyCtxt<'tcx>, free_regions: &'a FreeRegionMap<'tcx>) -> Self { + Self { tcx, free_regions } } pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { @@ -53,7 +49,7 @@ impl<'tcx> FreeRegionMap<'tcx> { // (with the exception that `'static: 'x` is not notable) pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { debug!("relate_regions(sub={:?}, sup={:?})", sub, sup); - if self.is_free_or_static(sub) && self.is_free(sup) { + if sub.is_free_or_static() && sup.is_free() { self.relation.add(sub, sup) } } @@ -72,7 +68,7 @@ impl<'tcx> FreeRegionMap<'tcx> { r_a: Region<'tcx>, r_b: Region<'tcx>, ) -> bool { - assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b)); + assert!(r_a.is_free_or_static() && r_b.is_free_or_static()); let re_static = tcx.lifetimes.re_static; if self.check_relation(re_static, r_b) { // `'a <= 'static` is always true, and not stored in the @@ -89,20 +85,6 @@ impl<'tcx> FreeRegionMap<'tcx> { r_a == r_b || self.relation.contains(r_a, r_b) } - /// True for free regions other than `'static`. - pub fn is_free(&self, r: Region<'_>) -> bool { - matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - - /// True if `r` is a free region or static of the sort that this - /// free region map can be used with. - pub fn is_free_or_static(&self, r: Region<'_>) -> bool { - match *r { - ty::ReStatic => true, - _ => self.is_free(r), - } - } - /// Computes the least-upper-bound of two free regions. In some /// cases, this is more conservative than necessary, in order to /// avoid making arbitrary choices. See @@ -114,8 +96,8 @@ impl<'tcx> FreeRegionMap<'tcx> { r_b: Region<'tcx>, ) -> Region<'tcx> { debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b); - assert!(self.is_free(r_a)); - assert!(self.is_free(r_b)); + assert!(r_a.is_free()); + assert!(r_b.is_free()); let result = if r_a == r_b { r_a } else { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 024f74099476c..84004d2b21f90 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -34,7 +34,7 @@ use super::InferCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_middle::infer::unify_key::ToType; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable}; use std::collections::hash_map::Entry; pub struct TypeFreshener<'a, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index c82685d1b70c9..e543ae1fcdab1 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -34,31 +34,27 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { T: Relate<'tcx>, { let span = self.trace.cause.span; + // First, we instantiate each bound region in the supertype with a + // fresh placeholder region. Note that this automatically creates + // a new universe if needed. + let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup); - self.infcx.commit_if_ok(|_| { - // First, we instantiate each bound region in the supertype with a - // fresh placeholder region. Note that this automatically creates - // a new universe if needed. - let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup); + // Next, we instantiate each bound region in the subtype + // with a fresh region variable. These region variables -- + // but no other pre-existing region variables -- can name + // the placeholders. + let sub_prime = self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub); - // Next, we instantiate each bound region in the subtype - // with a fresh region variable. These region variables -- - // but no other pre-existing region variables -- can name - // the placeholders. - let sub_prime = - self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub); + debug!("a_prime={:?}", sub_prime); + debug!("b_prime={:?}", sup_prime); - debug!("a_prime={:?}", sub_prime); - debug!("b_prime={:?}", sup_prime); + // Compare types now that bound regions have been replaced. + let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?; - // Compare types now that bound regions have been replaced. - let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?; - - debug!("higher_ranked_sub: OK result={result:?}"); - // NOTE: returning the result here would be dangerous as it contains - // placeholders which **must not** be named afterwards. - Ok(()) - }) + debug!("OK result={result:?}"); + // NOTE: returning the result here would be dangerous as it contains + // placeholders which **must not** be named afterwards. + Ok(()) } } @@ -126,7 +122,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // subtyping errors that it would have caught will now be // caught later on, during region checking. However, we // continue to use it for a transition period. - if self.tcx.sess.opts.debugging_opts.no_leak_check || self.skip_leak_check.get() { + if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check.get() { return Ok(()); } 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 455de47acef1b..3783cfb4cc5c8 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -47,7 +47,6 @@ pub(crate) fn resolve<'tcx>( #[derive(Clone)] pub struct LexicalRegionResolutions<'tcx> { pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>, - pub(crate) error_region: ty::Region<'tcx>, } #[derive(Copy, Clone, Debug)] @@ -120,13 +119,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ) -> LexicalRegionResolutions<'tcx> { let mut var_data = self.construct_var_data(self.tcx()); - // Dorky hack to cause `dump_constraints` to only get called - // if debug mode is enabled: - debug!( - "----() End constraint listing (context={:?}) {:?}---", - self.region_rels.context, - self.dump_constraints(self.region_rels) - ); + if cfg!(debug_assertions) { + self.dump_constraints(); + } let graph = self.construct_graph(); self.expand_givens(&graph); @@ -144,7 +139,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// empty region. The `expansion` phase will grow this larger. fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> { LexicalRegionResolutions { - error_region: tcx.lifetimes.re_static, values: IndexVec::from_fn_n( |vid| { let vid_universe = self.var_infos[vid].universe; @@ -156,8 +150,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) { - debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context); + #[instrument(level = "debug", skip(self))] + fn dump_constraints(&self) { for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() { debug!("Constraint {} => {:?}", idx, constraint); } @@ -314,7 +308,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Check for the case where we know that `'b: 'static` -- in that case, // `a <= b` for all `a`. - let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b); + let b_free_or_static = b.is_free_or_static(); if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) { return true; } @@ -324,7 +318,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // `lub` relationship defined below, since sometimes the "lub" // is actually the `postdom_upper_bound` (see // `TransitiveRelation` for more details). - let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a); + let a_free_or_static = a.is_free_or_static(); if a_free_or_static && b_free_or_static { return sub_free_regions(a, b); } @@ -868,10 +862,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(value, &mut false, |r, _db| match *r { - ty::ReVar(rid) => self.resolve_var(rid), - _ => r, - }) + tcx.fold_regions(value, |r, _db| self.resolve_region(tcx, r)) } fn value(&self, rid: RegionVid) -> &VarValue<'tcx> { @@ -882,12 +873,19 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { &mut self.values[rid] } - pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { - let result = match self.values[rid] { - VarValue::Value(r) => r, - VarValue::ErrorValue => self.error_region, + pub(crate) fn resolve_region( + &self, + tcx: TyCtxt<'tcx>, + r: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + let result = match *r { + ty::ReVar(rid) => match self.values[rid] { + VarValue::Value(r) => r, + VarValue::ErrorValue => tcx.lifetimes.re_static, + }, + _ => r, }; - debug!("resolve_var({:?}) = {:?}", rid, result); + debug!("resolve_region({:?}) = {:?}", r, result); result } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6f88b83a47321..c5a342c1ba2ca 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -15,17 +15,18 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::traits::select; +use rustc_middle::ty::abstract_const::AbstractConst; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; +use rustc_middle::ty::visit::TypeVisitable; pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; @@ -147,7 +148,7 @@ pub struct InferCtxtInner<'tcx> { /// for each body-id in this map, which will process the /// obligations within. This is expected to be done 'late enough' /// that all type inference variables have been bound and so forth. - region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, + region_obligations: Vec<RegionObligation<'tcx>>, undo_log: InferCtxtUndoLogs<'tcx>, @@ -171,7 +172,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn region_obligations(&self) -> &[(hir::HirId, RegionObligation<'tcx>)] { + pub fn region_obligations(&self) -> &[RegionObligation<'tcx>] { &self.region_obligations } @@ -319,7 +320,7 @@ pub struct InferCtxt<'a, 'tcx> { } /// See the `error_reporting` module for more details. -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub enum ValuePairs<'tcx> { Regions(ExpectedFound<ty::Region<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>), @@ -466,9 +467,6 @@ pub enum NllRegionVariableOrigin { /// from a `for<'a> T` binder). Meant to represent "any region". Placeholder(ty::PlaceholderRegion), - /// The variable we create to represent `'empty(U0)`. - RootEmptyRegion, - Existential { /// If this is true, then this variable was created to represent a lifetime /// bound in a `for` binder. For example, it might have been created to @@ -891,6 +889,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .region_constraints_added_in_snapshot(&snapshot.undo_snapshot) } + pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool { + 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); } @@ -1250,7 +1252,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let lexical_region_resolutions = LexicalRegionResolutions { - error_region: self.tcx.lifetimes.re_static, values: rustc_index::vec::IndexVec::from_elem_n( crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased), var_infos.len(), @@ -1267,7 +1268,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// `resolve_vars_if_possible` as well as `fully_resolve`. pub fn resolve_regions( &self, - region_context: DefId, outlives_env: &OutlivesEnvironment<'tcx>, ) -> Vec<RegionResolutionError<'tcx>> { let (var_infos, data) = { @@ -1286,8 +1286,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .into_infos_and_data() }; - let region_rels = - &RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map()); + let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data); @@ -1304,10 +1303,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// `resolve_vars_if_possible` as well as `fully_resolve`. pub fn resolve_regions_and_report_errors( &self, - region_context: DefId, + generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, ) { - let errors = self.resolve_regions(region_context, outlives_env); + let errors = self.resolve_regions(outlives_env); if !self.is_tainted_by_errors() { // As a heuristic, just skip reporting region errors @@ -1315,7 +1314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // this infcx was in use. This is totally hokey but // otherwise we have a hard time separating legit region // errors from silly ones. - self.report_region_errors(&errors); + self.report_region_errors(generic_param_scope, &errors); } } @@ -1445,7 +1444,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// `resolve_vars_if_possible()`. pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)> where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value() } @@ -1657,14 +1656,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { unevaluated: ty::Unevaluated<'tcx>, span: Option<Span>, ) -> EvalToValTreeResult<'tcx> { - let substs = self.resolve_vars_if_possible(unevaluated.substs); + let mut substs = self.resolve_vars_if_possible(unevaluated.substs); debug!(?substs); // Postpone the evaluation of constants whose substs depend on inference // variables if substs.has_infer_types_or_consts() { - debug!("substs have infer types or consts: {:?}", substs); - return Err(ErrorHandled::TooGeneric); + let ac = AbstractConst::new(self.tcx, unevaluated.shrink()); + if let Ok(None) = ac { + substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did); + } else { + return Err(ErrorHandled::TooGeneric); + } } let param_env_erased = self.tcx.erase_regions(param_env); diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 846e7f7b92155..bab4f3e9e362f 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -27,8 +27,8 @@ use crate::infer::{ConstVarValue, ConstVariableValue}; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_span::Span; use std::fmt::Debug; @@ -810,7 +810,7 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>( + fn visit_binder<T: TypeVisitable<'tcx>>( &mut self, t: &ty::Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 7684d861f3c93..f11701bba6f43 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -5,11 +5,12 @@ use hir::{HirId, OpaqueTyOrigin}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; -use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::{ - self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor, + self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitor, }; use rustc_span::Span; @@ -39,37 +40,28 @@ pub struct OpaqueTypeDecl<'tcx> { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// This is a backwards compatibility hack to prevent breaking changes from - /// lazy TAIT around RPIT handling. - pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>( + pub fn replace_opaque_types_with_inference_vars( &self, - value: T, + ty: Ty<'tcx>, body_id: HirId, span: Span, - code: ObligationCauseCode<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> InferOk<'tcx, T> { - if !value.has_opaque_types() { - return InferOk { value, obligations: vec![] }; + ) -> InferOk<'tcx, Ty<'tcx>> { + if !ty.has_opaque_types() { + return InferOk { value: ty, obligations: vec![] }; } let mut obligations = vec![]; - let value = value.fold_with(&mut ty::fold::BottomUpFolder { + let replace_opaque_type = |def_id| self.opaque_type_origin(def_id, span).is_some(); + let value = ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, ct_op: |ct| ct, ty_op: |ty| match *ty.kind() { - // Closures can't create hidden types for opaque types of their parent, as they - // do not have all the outlives information available. Also `type_of` looks for - // hidden types in the owner (so the closure's parent), so it would not find these - // definitions. - ty::Opaque(def_id, _substs) - if matches!( - self.opaque_type_origin(def_id, span), - Some(OpaqueTyOrigin::FnReturn(..)) - ) => - { - let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span }; - let cause = ObligationCause::new(span, body_id, code.clone()); + ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => { + let def_span = self.tcx.def_span(def_id); + let span = if span.contains(def_span) { def_span } else { span }; + let code = traits::ObligationCauseCode::OpaqueReturnType(None); + let cause = ObligationCause::new(span, body_id, code); // FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind // for opaque types, and then use that kind to fix the spans for type errors // that we see later on. @@ -103,7 +95,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { - ty::Opaque(def_id, substs) => { + ty::Opaque(def_id, substs) if def_id.is_local() => { let origin = if self.defining_use_anchor.is_some() { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose @@ -470,7 +462,7 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP> where OP: FnMut(ty::Region<'tcx>), { - fn visit_binder<T: TypeFoldable<'tcx>>( + fn visit_binder<T: TypeVisitable<'tcx>>( &mut self, t: &ty::Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 5ea096f5cc2c9..b2d7f4a663ae4 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -4,7 +4,7 @@ use rustc_data_structures::sso::SsoHashSet; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use smallvec::{smallvec, SmallVec}; #[derive(Debug)] @@ -190,7 +190,11 @@ fn compute_components<'tcx>( } } -fn compute_components_recursive<'tcx>( +/// Collect [Component]s for *all* the substs of `parent`. +/// +/// This should not be used to get the components of `parent` itself. +/// Use [push_outlives_components] instead. +pub(super) fn compute_components_recursive<'tcx>( tcx: TyCtxt<'tcx>, parent: GenericArg<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 9ddda7b92eb5a..b897de7315a02 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,8 +1,6 @@ use crate::infer::free_regions::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; use super::explicit_outlives_bounds; @@ -31,9 +29,7 @@ pub struct OutlivesEnvironment<'tcx> { pub param_env: ty::ParamEnv<'tcx>, free_region_map: FreeRegionMap<'tcx>, - // Contains, for each body B that we are checking (that is, the fn - // item, but also any nested closures), the set of implied region - // bounds that are in scope in that particular body. + // Contains the implied region bounds in scope for our current body. // // Example: // @@ -43,24 +39,15 @@ pub struct OutlivesEnvironment<'tcx> { // } // body B0 // ``` // - // Here, for body B0, the list would be `[T: 'a]`, because we + // Here, when checking the body B0, the list would be `[T: 'a]`, because we // infer that `T` must outlive `'a` from the implied bounds on the // fn declaration. // - // For the body B1, the list would be `[T: 'a, T: 'b]`, because we + // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we // also can see that -- within the closure body! -- `T` must // outlive `'b`. This is not necessarily true outside the closure // body, since the closure may never be called. - // - // We collect this map as we descend the tree. We then use the - // results when proving outlives obligations like `T: 'x` later - // (e.g., if `T: 'x` must be proven within the body B1, then we - // know it is true if either `'a: 'x` or `'b: 'x`). - region_bound_pairs_map: FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, - - // Used to compute `region_bound_pairs_map`: contains the set of - // in-scope region-bound pairs thus far. - region_bound_pairs_accum: RegionBoundPairs<'tcx>, + region_bound_pairs: RegionBoundPairs<'tcx>, } /// "Region-bound pairs" tracks outlives relations that are known to @@ -73,8 +60,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { let mut env = OutlivesEnvironment { param_env, free_region_map: Default::default(), - region_bound_pairs_map: Default::default(), - region_bound_pairs_accum: vec![], + region_bound_pairs: Default::default(), }; env.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); @@ -87,62 +73,9 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { &self.free_region_map } - /// Borrows current value of the `region_bound_pairs`. - pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>> { - &self.region_bound_pairs_map - } - - /// This is a hack to support the old-school regionck, which - /// processes region constraints from the main function and the - /// closure together. In that context, when we enter a closure, we - /// want to be able to "save" the state of the surrounding a - /// function. We can then add implied bounds and the like from the - /// closure arguments into the environment -- these should only - /// apply in the closure body, so once we exit, we invoke - /// `pop_snapshot_post_typeck_child` to remove them. - /// - /// Example: - /// - /// ```ignore (pseudo-rust) - /// fn foo<T>() { - /// callback(for<'a> |x: &'a T| { - /// // ^^^^^^^ not legal syntax, but probably should be - /// // within this closure body, `T: 'a` holds - /// }) - /// } - /// ``` - /// - /// This "containment" of closure's effects only works so well. In - /// particular, we (intentionally) leak relationships between free - /// regions that are created by the closure's bounds. The case - /// where this is useful is when you have (e.g.) a closure with a - /// signature like `for<'a, 'b> fn(x: &'a &'b u32)` -- in this - /// case, we want to keep the relationship `'b: 'a` in the - /// free-region-map, so that later if we have to take `LUB('b, - /// 'a)` we can get the result `'b`. - /// - /// I have opted to keep **all modifications** to the - /// free-region-map, however, and not just those that concern free - /// variables bound in the closure. The latter seems more correct, - /// but it is not the existing behavior, and I could not find a - /// case where the existing behavior went wrong. In any case, it - /// seems like it'd be readily fixed if we wanted. There are - /// similar leaks around givens that seem equally suspicious, to - /// be honest. --nmatsakis - pub fn push_snapshot_pre_typeck_child(&self) -> usize { - self.region_bound_pairs_accum.len() - } - - /// See `push_snapshot_pre_typeck_child`. - pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) { - self.region_bound_pairs_accum.truncate(len); - } - - /// Save the current set of region-bound pairs under the given `body_id`. - pub fn save_implied_bounds(&mut self, body_id: hir::HirId) { - let old = - self.region_bound_pairs_map.insert(body_id, self.region_bound_pairs_accum.clone()); - assert!(old.is_none()); + /// Borrows current `region_bound_pairs`. + pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { + &self.region_bound_pairs } /// Processes outlives bounds that are known to hold, whether from implied or other sources. @@ -164,11 +97,10 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); match outlives_bound { OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b))); + self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); } OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs_accum - .push((r_a, GenericKind::Projection(projection_b))); + self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); } OutlivesBound::RegionSubRegion(r_a, r_b) => { if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a268493b28f63..a57971bfb697d 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -60,18 +60,17 @@ //! imply that `'b: 'a`. use crate::infer::outlives::components::{push_outlives_components, Component}; +use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::{ self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, }; use crate::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; - -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::undo_log::UndoLogs; -use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable}; use smallvec::smallvec; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { @@ -80,16 +79,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// and later processed by regionck, when full type information is /// available (see `region_obligations` field for more /// information). - pub fn register_region_obligation( - &self, - body_id: hir::HirId, - obligation: RegionObligation<'tcx>, - ) { - debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation); - + #[instrument(level = "debug", skip(self))] + pub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>) { let mut inner = self.inner.borrow_mut(); inner.undo_log.push(UndoLog::PushRegionObligation); - inner.region_obligations.push((body_id, obligation)); + inner.region_obligations.push(obligation); } pub fn register_region_obligation_with_cause( @@ -109,14 +103,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) }); - self.register_region_obligation( - cause.body_id, - RegionObligation { sup_type, sub_region, origin }, - ); + self.register_region_obligation(RegionObligation { sup_type, sub_region, origin }); } /// Trait queries just want to pass back type obligations "as is" - pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> { + pub fn take_registered_region_obligations(&self) -> Vec<RegionObligation<'tcx>> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } @@ -141,17 +132,13 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// `('a, K)` in this list tells us that the bounds in scope /// indicate that `K: 'a`, where `K` is either a generic /// parameter like `T` or a projection like `T::Item`. - /// - `implicit_region_bound`: if some, this is a region bound - /// that is considered to hold for all type parameters (the - /// function body). /// - `param_env` is the parameter environment for the enclosing function. /// - `body_id` is the body-id whose region obligations are being /// processed. - #[instrument(level = "debug", skip(self, region_bound_pairs_map))] + #[instrument(level = "debug", skip(self, region_bound_pairs))] pub fn process_registered_region_obligations( &self, - region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, - implicit_region_bound: Option<ty::Region<'tcx>>, + region_bound_pairs: &RegionBoundPairs<'tcx>, param_env: ty::ParamEnv<'tcx>, ) { assert!( @@ -161,7 +148,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let my_region_obligations = self.take_registered_region_obligations(); - for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations { + for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { debug!( "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}", sup_type, sub_region, origin @@ -169,23 +156,24 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let sup_type = self.resolve_vars_if_possible(sup_type); - if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) { - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - ®ion_bound_pairs, - implicit_region_bound, - param_env, - ); - outlives.type_must_outlive(origin, sup_type, sub_region); - } else { - self.tcx.sess.delay_span_bug( - origin.span(), - &format!("no region-bound-pairs for {:?}", body_id), - ); - } + let outlives = + &mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env); + outlives.type_must_outlive(origin, sup_type, sub_region); } } + + pub fn check_region_obligations_and_report_errors( + &self, + generic_param_scope: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, + ) { + self.process_registered_region_obligations( + outlives_env.region_bound_pairs(), + outlives_env.param_env, + ); + + self.resolve_regions_and_report_errors(generic_param_scope, outlives_env) + } } /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 9f71ebae99e5b..772e297b7b445 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -1,7 +1,7 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{ self, error::TypeError, diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 191f5f18ec2a6..faa0a18f93d9a 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,12 +1,15 @@ +use crate::infer::outlives::components::{compute_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; use rustc_data_structures::sso::SsoHashSet; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; +use rustc_middle::ty::subst::{GenericArg, Subst}; use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; +use smallvec::smallvec; + /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` /// obligation into a series of `'a: 'b` constraints and "verifys", as /// described on the module comment. The final constraints are emitted @@ -16,6 +19,11 @@ use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; pub struct VerifyBoundCx<'cx, 'tcx> { tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, + /// During borrowck, if there are no outlives bounds on a generic + /// parameter `T`, we assume that `T: 'in_fn_body` holds. + /// + /// Outside of borrowck the only way to prove `T: '?0` is by + /// setting `'?0` to `'empty`. implicit_region_bound: Option<ty::Region<'tcx>>, param_env: ty::ParamEnv<'tcx>, } @@ -42,43 +50,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } } - fn type_bound( - &self, - ty: Ty<'tcx>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, - ) -> VerifyBound<'tcx> { - match *ty.kind() { - ty::Param(p) => self.param_bound(p), - ty::Projection(data) => self.projection_bound(data, visited), - ty::FnDef(_, substs) => { - // HACK(eddyb) ignore lifetimes found shallowly in `substs`. - // This is inconsistent with `ty::Adt` (including all substs), - // but consistent with previous (accidental) behavior. - // See https://github.com/rust-lang/rust/issues/70917 - // for further background and discussion. - let mut bounds = substs - .iter() - .filter_map(|child| match child.unpack() { - GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), - GenericArgKind::Lifetime(_) => None, - GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)), - }) - .filter(|bound| { - // Remove bounds that must hold, since they are not interesting. - !bound.must_hold() - }); - - match (bounds.next(), bounds.next()) { - (Some(first), None) => first, - (first, second) => VerifyBound::AllBounds( - first.into_iter().chain(second).chain(bounds).collect(), - ), - } - } - _ => self.recursive_bound(ty.into(), visited), - } - } - fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { debug!("param_bound(param_ty={:?})", param_ty); @@ -183,27 +154,24 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { .map(|r| VerifyBound::OutlivedBy(r)); // see the extensive comment in projection_must_outlive - let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); - let recursive_bound = self.recursive_bound(ty.into(), visited); + let recursive_bound = { + let mut components = smallvec![]; + let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); + compute_components_recursive(self.tcx, ty.into(), &mut components, visited); + self.bound_from_components(&components, visited) + }; VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound) } - fn recursive_bound( + fn bound_from_components( &self, - parent: GenericArg<'tcx>, + components: &[Component<'tcx>], visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { - let mut bounds = parent - .walk_shallow(visited) - .filter_map(|child| match child.unpack() { - GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), - GenericArgKind::Lifetime(lt) => { - // Ignore late-bound regions. - if !lt.is_late_bound() { Some(VerifyBound::OutlivedBy(lt)) } else { None } - } - GenericArgKind::Const(_) => Some(self.recursive_bound(child, visited)), - }) + let mut bounds = components + .iter() + .map(|component| self.bound_from_single_component(component, visited)) .filter(|bound| { // Remove bounds that must hold, since they are not interesting. !bound.must_hold() @@ -217,6 +185,32 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } } + fn bound_from_single_component( + &self, + component: &Component<'tcx>, + visited: &mut SsoHashSet<GenericArg<'tcx>>, + ) -> VerifyBound<'tcx> { + match *component { + Component::Region(lt) => VerifyBound::OutlivedBy(lt), + Component::Param(param_ty) => self.param_bound(param_ty), + Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited), + Component::EscapingProjection(ref components) => { + self.bound_from_components(components, visited) + } + Component::UnresolvedInferenceVariable(v) => { + // ignore this, we presume it will yield an error + // later, since if a type variable is not resolved by + // this point it never will be + self.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!("unresolved inference variable in outlives: {:?}", v), + ); + // add a bound that never holds + VerifyBound::AnyBound(vec![]) + } + } + } + /// Searches the environment for where-clauses like `G: 'a` where /// `G` is either some type parameter `T` or a projection like /// `T::Item`. Returns a vector of the `'a` bounds it can find. @@ -263,8 +257,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // fn foo<'a, A>(x: &'a A) { x.bar() } // // The problem is that the type of `x` is `&'a A`. To be - // well-formed, then, A must be lower-generic by `'a`, but we - // don't know that this holds from first principles. + // well-formed, then, A must outlive `'a`, but we don't know that + // this holds from first principles. let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| { debug!( "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}", diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 19f83e3377a67..c5747ecf702a7 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -165,7 +165,7 @@ pub struct Verify<'tcx> { pub bound: VerifyBound<'tcx>, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), Projection(ty::ProjectionTy<'tcx>), @@ -272,7 +272,7 @@ pub enum VerifyBound<'tcx> { /// } /// } /// ``` -#[derive(Debug, Copy, Clone, TypeFoldable)] +#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable)] pub struct VerifyIfEq<'tcx> { /// Type which must match the generic `G` pub ty: Ty<'tcx>, diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index d830000b65f69..3d99f0958f7f9 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,8 +1,9 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{FixupError, FixupResult, InferCtxt, Span}; use rustc_middle::mir; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable, TypeVisitor}; -use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use std::ops::ControlFlow; @@ -92,7 +93,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { .borrow_mut() .unwrap_region_constraints() .opportunistic_resolve_var(rid); - self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved)) + TypeFolder::tcx(self).reuse_or_mk_region(r, ty::ReVar(resolved)) } _ => r, } @@ -179,15 +180,13 @@ struct FullTypeResolver<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, } -impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { +impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { type Error = FixupError<'tcx>; fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.infcx.tcx } -} -impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { if !t.needs_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... @@ -207,13 +206,13 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> { match *r { - ty::ReVar(rid) => Ok(self + ty::ReVar(_) => Ok(self .infcx .lexical_region_resolutions .borrow() .as_ref() .expect("region resolution not performed") - .resolve_var(rid)), + .resolve_region(self.infcx.tcx, r)), _ => Ok(r), } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index d0c6d8d16ebfa..b27571275b733 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -4,8 +4,8 @@ use super::SubregionOrigin; use crate::infer::combine::ConstEquateRelation; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::Obligation; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use std::mem; diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 1b696f21cbcf4..74a26ebc39f81 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -185,6 +185,10 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { }) } + pub(crate) fn opaque_types_in_snapshot(&self, s: &Snapshot<'tcx>) -> bool { + self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..))) + } + pub(crate) fn region_constraints( &self, ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone { diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 7769a68ba2a66..490ba52503fb2 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -18,7 +18,7 @@ #![feature(control_flow_enum)] #![feature(extend_one)] #![feature(label_break_value)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index d297640c14027..95b6c4ce1f296 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -18,18 +18,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_item_def_id: DefId, requirement: &dyn fmt::Display, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let msg = "impl has stricter requirements than trait"; - let sp = self.tcx.sess.source_map().guess_head_span(error_span); + let mut err = struct_span_err!( + self.tcx.sess, + error_span, + E0276, + "impl has stricter requirements than trait" + ); - let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg); - - if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let span = self.tcx.sess.source_map().guess_head_span(trait_item_span); + if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); err.span_label(span, format!("definition of `{}` from trait", item_name)); } - err.span_label(sp, format!("impl has extra requirement {}", requirement)); + err.span_label(error_span, format!("impl has extra requirement {}", requirement)); err } @@ -46,7 +47,6 @@ pub fn report_object_safety_error<'tcx>( hir::Node::Item(item) => Some(item.ident.span), _ => None, }); - let span = tcx.sess.source_map().guess_head_span(span); let mut err = struct_span_err!( tcx.sess, span, @@ -85,8 +85,7 @@ pub fn report_object_safety_error<'tcx>( let has_multi_span = !multi_span.is_empty(); let mut note_span = MultiSpan::from_spans(multi_span.clone()); if let (Some(trait_span), true) = (trait_span, has_multi_span) { - note_span - .push_span_label(trait_span, "this trait cannot be made into an object...".to_string()); + note_span.push_span_label(trait_span, "this trait cannot be made into an object..."); } for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index b84ed3dc68937..5d22f9f972e10 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, } -#[derive(Clone, TypeFoldable)] +#[derive(Clone, TypeFoldable, TypeVisitable)] pub struct Normalized<'tcx, T> { pub value: T, pub obligations: Vec<PredicateObligation<'tcx>>, @@ -203,7 +203,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => { info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); let mut ty = ty.clone(); - if result == EvaluationResult::EvaluatedToOk { + if result.must_apply_considering_regions() { ty.obligations = vec![]; } map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) }); diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 82ee4bb29e88b..573d2d1e33016 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -1,7 +1,8 @@ use crate::traits; use crate::traits::project::Normalized; use rustc_middle::ty; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable}; +use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor}; use std::fmt; use std::ops::ControlFlow; @@ -68,7 +69,9 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx param_env: self.param_env.try_fold_with(folder)?, }) } +} +impl<'tcx, O: TypeVisitable<'tcx>> TypeVisitable<'tcx> for traits::Obligation<'tcx, O> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.predicate.visit_with(visitor)?; self.param_env.visit_with(visitor) diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 26b1b9948a047..1ecbc876c8d8a 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -11,7 +11,7 @@ libloading = "0.7.1" tracing = "0.1" rustc-rayon-core = { version = "0.4.0", optional = true } rayon = { version = "0.4.0", package = "rustc-rayon", optional = true } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } @@ -46,7 +46,6 @@ rustc_query_impl = { path = "../rustc_query_impl" } rustc_resolve = { path = "../rustc_resolve" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tempfile = "3.2" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index e7563933c88ac..6c7ddb4531ef8 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -300,7 +300,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R ); } - let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); + let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); let compiler = Compiler { sess, @@ -333,7 +333,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se tracing::trace!("run_compiler"); util::run_in_thread_pool_with_globals( config.opts.edition, - config.opts.debugging_opts.threads, + config.opts.unstable_opts.threads, || create_compiler_and_run(config, f), ) } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 502afa493fe66..334a595a88ae6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -5,19 +5,15 @@ 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::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; -use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; -use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::StableCrateId; use rustc_hir::definitions::Definitions; -use rustc_hir::Crate; -use rustc_lint::{EarlyCheckNode, LintStore}; +use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; -use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::query::{ExternProviders, Providers}; @@ -30,14 +26,13 @@ use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn}; -use rustc_session::output::{filename_for_input, filename_for_metadata}; +use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; use rustc_typeck as typeck; -use tempfile::Builder as TempFileBuilder; use tracing::{info, warn}; use std::any::Any; @@ -59,16 +54,16 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { } })?; - if sess.opts.debugging_opts.input_stats { + if sess.opts.unstable_opts.input_stats { eprintln!("Lines of code: {}", sess.source_map().count_lines()); eprintln!("Pre-expansion node count: {}", count_nodes(&krate)); } - if let Some(ref s) = sess.opts.debugging_opts.show_span { + if let Some(ref s) = sess.opts.unstable_opts.show_span { rustc_ast_passes::show_span::run(sess.diagnostic(), s, &krate); } - if sess.opts.debugging_opts.hir_stats { + if sess.opts.unstable_opts.hir_stats { hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); } @@ -182,7 +177,7 @@ pub fn register_plugins<'a>( rustc_builtin_macros::cmdline_attrs::inject( krate, &sess.parse_sess, - &sess.opts.debugging_opts.crate_attr, + &sess.opts.unstable_opts.crate_attr, ) }); @@ -214,7 +209,7 @@ pub fn register_plugins<'a>( } let mut lint_store = rustc_lint::new_lint_store( - sess.opts.debugging_opts.no_interleave_lints, + sess.opts.unstable_opts.no_interleave_lints, sess.unstable_options(), ); register_lints(sess, &mut lint_store); @@ -328,21 +323,24 @@ pub fn configure_and_expand( let cfg = rustc_expand::expand::ExpansionConfig { features: Some(features), recursion_limit, - trace_mac: sess.opts.debugging_opts.trace_macros, + trace_mac: sess.opts.unstable_opts.trace_macros, should_test: sess.opts.test, - span_debug: sess.opts.debugging_opts.span_debug, - proc_macro_backtrace: sess.opts.debugging_opts.proc_macro_backtrace, + span_debug: sess.opts.unstable_opts.span_debug, + proc_macro_backtrace: sess.opts.unstable_opts.proc_macro_backtrace, ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; let lint_store = LintStoreExpandImpl(lint_store); let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store)); - // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); // The rest is error reporting + sess.parse_sess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| { + buffered_lints.append(&mut ecx.buffered_early_lint); + }); + sess.time("check_unused_macros", || { ecx.check_unused_macros(); }); @@ -414,11 +412,11 @@ pub fn configure_and_expand( // Done with macro expansion! - if sess.opts.debugging_opts.input_stats { + if sess.opts.unstable_opts.input_stats { eprintln!("Post-expansion node count: {}", count_nodes(&krate)); } - if sess.opts.debugging_opts.hir_stats { + if sess.opts.unstable_opts.hir_stats { hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); } @@ -482,37 +480,6 @@ pub fn configure_and_expand( Ok(krate) } -fn lower_to_hir<'tcx>( - sess: &Session, - definitions: &mut Definitions, - cstore: &CrateStoreDyn, - resolutions: &ty::ResolverOutputs, - resolver: ty::ResolverAstLowering, - krate: Rc<ast::Crate>, - arena: &'tcx rustc_ast_lowering::Arena<'tcx>, -) -> &'tcx Crate<'tcx> { - // Lower AST to HIR. - let hir_crate = rustc_ast_lowering::lower_crate( - sess, - &krate, - definitions, - cstore, - resolutions, - resolver, - arena, - ); - - // Drop AST to free memory - sess.time("drop_ast", || std::mem::drop(krate)); - - // Discard hygiene data, which isn't required after lowering to HIR. - if !sess.opts.debugging_opts.keep_hygiene_data { - rustc_span::hygiene::clear_syntax_context_map(); - } - - hir_crate -} - // Returns all the paths that correspond to generated files. fn generated_output_paths( sess: &Session, @@ -532,7 +499,7 @@ fn generated_output_paths( out_filenames.push(p); } } - OutputType::DepInfo if sess.opts.debugging_opts.dep_info_omit_d_target => { + OutputType::DepInfo if sess.opts.unstable_opts.dep_info_omit_d_target => { // Don't add the dep-info output when omitting it from dep-info targets } _ => { @@ -630,7 +597,7 @@ fn write_out_deps( files.extend(extra_tracked_files); if sess.binary_dep_depinfo() { - if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend { + if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { // If the backend name contain a `.`, it is the path to an external dynamic // library. If not, it is not a path. @@ -777,6 +744,7 @@ pub fn prepare_outputs( pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; + providers.hir_crate = rustc_ast_lowering::lower_to_hir; proc_macro_decls::provide(providers); rustc_const_eval::provide(providers); rustc_middle::hir::provide(providers); @@ -823,7 +791,7 @@ impl<'tcx> QueryContext<'tcx> { pub fn create_global_ctxt<'tcx>( compiler: &'tcx Compiler, lint_store: Lrc<LintStore>, - krate: Rc<ast::Crate>, + krate: Lrc<ast::Crate>, dep_graph: DepGraph, resolver: Rc<RefCell<BoxedResolver>>, outputs: OutputFilenames, @@ -831,29 +799,17 @@ pub fn create_global_ctxt<'tcx>( queries: &'tcx OnceCell<TcxQueries<'tcx>>, global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>, arena: &'tcx WorkerLocal<Arena<'tcx>>, - hir_arena: &'tcx WorkerLocal<rustc_ast_lowering::Arena<'tcx>>, + hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>, ) -> QueryContext<'tcx> { // We're constructing the HIR here; we don't care what we will // read, since we haven't even constructed the *input* to // incr. comp. yet. dep_graph.assert_ignored(); - let (mut definitions, cstore, resolver_outputs, resolver_for_lowering) = + let (definitions, cstore, resolver_outputs, resolver_for_lowering) = BoxedResolver::to_resolver_outputs(resolver); let sess = &compiler.session(); - - // Lower AST to HIR. - let krate = lower_to_hir( - sess, - &mut definitions, - &*cstore, - &resolver_outputs, - resolver_for_lowering, - krate, - hir_arena, - ); - let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); let codegen_backend = compiler.codegen_backend(); @@ -877,9 +833,11 @@ pub fn create_global_ctxt<'tcx>( sess, lint_store, arena, + hir_arena, definitions, cstore, resolver_outputs, + resolver_for_lowering, krate, dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), @@ -969,9 +927,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("MIR_effect_checking", || { for def_id in tcx.hir().body_owners() { tcx.ensure().thir_check_unsafety(def_id); - if !tcx.sess.opts.debugging_opts.thir_unsafeck { + if !tcx.sess.opts.unstable_opts.thir_unsafeck { rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); } + tcx.ensure().has_ffi_unwind_calls(def_id); if tcx.hir().body_const_context(def_id).is_some() { tcx.ensure() @@ -1030,69 +989,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { Ok(()) } -fn encode_and_write_metadata( - tcx: TyCtxt<'_>, - outputs: &OutputFilenames, -) -> (EncodedMetadata, bool) { - #[derive(PartialEq, Eq, PartialOrd, Ord)] - enum MetadataKind { - None, - Uncompressed, - Compressed, - } - - let metadata_kind = tcx - .sess - .crate_types() - .iter() - .map(|ty| match *ty { - CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None, - - CrateType::Rlib => MetadataKind::Uncompressed, - - CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed, - }) - .max() - .unwrap_or(MetadataKind::None); - - let metadata = match metadata_kind { - MetadataKind::None => EncodedMetadata::new(), - MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx), - }; - - let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); - - let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); - if need_metadata_file { - let crate_name = tcx.crate_name(LOCAL_CRATE); - let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs); - // To avoid races with another rustc process scanning the output directory, - // we need to write the file somewhere else and atomically move it to its - // final destination, with an `fs::rename` call. In order for the rename to - // always succeed, the temporary file needs to be on the same filesystem, - // which is why we create it inside the output directory specifically. - let metadata_tmpdir = TempFileBuilder::new() - .prefix("rmeta") - .tempdir_in(out_filename.parent().unwrap()) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); - let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); - let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir); - if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) { - tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); - } - if tcx.sess.opts.json_artifact_notifications { - tcx.sess - .parse_sess - .span_diagnostic - .emit_artifact_notification(&out_filename, "metadata"); - } - } - - let need_metadata_module = metadata_kind == MetadataKind::Compressed; - - (metadata, need_metadata_module) -} - /// Runs the codegen backend, after which the AST and analysis can /// be discarded. pub fn start_codegen<'tcx>( @@ -1102,7 +998,8 @@ pub fn start_codegen<'tcx>( ) -> Box<dyn Any> { info!("Pre-codegen\n{:?}", tcx.debug_stats()); - let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs); + let (metadata, need_metadata_module) = + rustc_metadata::fs::encode_and_write_metadata(tcx, outputs); let codegen = tcx.sess.time("codegen_crate", move || { codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 136f0443fa0a3..73402ae084206 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -72,13 +72,13 @@ pub struct Queries<'tcx> { queries: OnceCell<TcxQueries<'tcx>>, arena: WorkerLocal<Arena<'tcx>>, - hir_arena: WorkerLocal<rustc_ast_lowering::Arena<'tcx>>, + hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>, dep_graph_future: Query<Option<DepGraphFuture>>, parse: Query<ast::Crate>, crate_name: Query<String>, register_plugins: Query<(ast::Crate, Lrc<LintStore>)>, - expansion: Query<(Rc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>, + expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>, dep_graph: Query<DepGraph>, prepare_outputs: Query<OutputFilenames>, global_ctxt: Query<QueryContext<'tcx>>, @@ -92,7 +92,7 @@ impl<'tcx> Queries<'tcx> { gcx: OnceCell::new(), queries: OnceCell::new(), arena: WorkerLocal::new(|_| Arena::default()), - hir_arena: WorkerLocal::new(|_| rustc_ast_lowering::Arena::default()), + hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), dep_graph_future: Default::default(), parse: Default::default(), crate_name: Default::default(), @@ -164,7 +164,7 @@ impl<'tcx> Queries<'tcx> { pub fn expansion( &self, - ) -> Result<&Query<(Rc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> { + ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> { tracing::trace!("expansion"); self.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); @@ -180,7 +180,7 @@ impl<'tcx> Queries<'tcx> { let krate = resolver.access(|resolver| { passes::configure_and_expand(sess, &lint_store, krate, &crate_name, resolver) })?; - Ok((Rc::new(krate), Rc::new(RefCell::new(resolver)), lint_store)) + Ok((Lrc::new(krate), Rc::new(RefCell::new(resolver)), lint_store)) }) } @@ -357,7 +357,7 @@ impl Linker { return Ok(()); } - if sess.opts.debugging_opts.no_link { + if sess.opts.unstable_opts.no_link { let encoded = CodegenResults::serialize_rlink(&codegen_results); let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); std::fs::write(&rlink_file, encoded).map_err(|err| { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 30a29ed6ed38f..9c0b534798e39 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -629,14 +629,14 @@ fn test_top_level_options_tracked_no_crate() { } #[test] -fn test_debugging_options_tracking_hash() { +fn test_unstable_options_tracking_hash() { let reference = Options::default(); let mut opts = Options::default(); macro_rules! untracked { ($name: ident, $non_default_value: expr) => { - assert_ne!(opts.debugging_opts.$name, $non_default_value); - opts.debugging_opts.$name = $non_default_value; + assert_ne!(opts.unstable_opts.$name, $non_default_value); + opts.unstable_opts.$name = $non_default_value; assert_same_hash(&reference, &opts); }; } @@ -649,6 +649,7 @@ fn test_debugging_options_tracking_hash() { untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); + untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string())); untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dir, String::from("abc")); @@ -689,7 +690,6 @@ fn test_debugging_options_tracking_hash() { untracked!(span_debug, true); untracked!(span_free_formats, true); untracked!(temps_dir, Some(String::from("abc"))); - untracked!(terminal_width, Some(80)); untracked!(threads, 99); untracked!(time, true); untracked!(time_llvm_passes, true); @@ -705,8 +705,8 @@ fn test_debugging_options_tracking_hash() { macro_rules! tracked { ($name: ident, $non_default_value: expr) => { opts = reference.clone(); - assert_ne!(opts.debugging_opts.$name, $non_default_value); - opts.debugging_opts.$name = $non_default_value; + assert_ne!(opts.unstable_opts.$name, $non_default_value); + opts.unstable_opts.$name = $non_default_value; assert_different_hash(&reference, &opts); }; } @@ -733,6 +733,7 @@ fn test_debugging_options_tracking_hash() { tracked!(dep_info_omit_d_target, true); tracked!(drop_tracking, true); tracked!(dual_proc_macros, true); + tracked!(dwarf_version, Some(5)); tracked!(fewer_names, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); @@ -803,8 +804,8 @@ fn test_debugging_options_tracking_hash() { macro_rules! tracked_no_crate_hash { ($name: ident, $non_default_value: expr) => { opts = reference.clone(); - assert_ne!(opts.debugging_opts.$name, $non_default_value); - opts.debugging_opts.$name = $non_default_value; + assert_ne!(opts.unstable_opts.$name, $non_default_value); + opts.unstable_opts.$name = $non_default_value; assert_non_crate_hash_different(&reference, &opts); }; } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index fb9258eb4a938..97856ecf22c66 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -10,7 +10,7 @@ use rustc_errors::registry::Registry; use rustc_middle::ty::tls; use rustc_parse::validate_attr; #[cfg(parallel_compiler)] -use rustc_query_impl::QueryCtxt; +use rustc_query_impl::{QueryContext, QueryCtxt}; use rustc_session as session; use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; @@ -48,7 +48,10 @@ pub fn add_configuration( ) { let tf = sym::target_feature; - let target_features = codegen_backend.target_features(sess); + let unstable_target_features = codegen_backend.target_features(sess, true); + sess.unstable_target_features.extend(unstable_target_features.iter().cloned()); + + let target_features = codegen_backend.target_features(sess, false); sess.target_features.extend(target_features.iter().cloned()); cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat)))); @@ -76,7 +79,7 @@ pub fn create_session( } else { get_codegen_backend( &sopts.maybe_sysroot, - sopts.debugging_opts.codegen_backend.as_ref().map(|name| &name[..]), + sopts.unstable_opts.codegen_backend.as_ref().map(|name| &name[..]), ) }; @@ -86,9 +89,9 @@ pub fn create_session( let bundle = match rustc_errors::fluent_bundle( sopts.maybe_sysroot.clone(), sysroot_candidates(), - sopts.debugging_opts.translate_lang.clone(), - sopts.debugging_opts.translate_additional_ftl.as_deref(), - sopts.debugging_opts.translate_directionality_markers, + sopts.unstable_opts.translate_lang.clone(), + sopts.unstable_opts.translate_additional_ftl.as_deref(), + sopts.unstable_opts.translate_directionality_markers, ) { Ok(bundle) => bundle, Err(e) => { @@ -166,20 +169,12 @@ pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( unsafe fn handle_deadlock() { let registry = rustc_rayon_core::Registry::current(); - let context = tls::get_tlv(); - assert!(context != 0); - rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>(); - let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>); - - let session_globals = rustc_span::with_session_globals(|sg| sg as *const _); - let session_globals = &*session_globals; - thread::spawn(move || { - tls::enter_context(icx, |_| { - rustc_span::set_session_globals_then(session_globals, || { - tls::with(|tcx| QueryCtxt::from_tcx(tcx).deadlock(®istry)) - }) - }); + let query_map = tls::with(|tcx| { + QueryCtxt::from_tcx(tcx) + .try_collect_active_jobs() + .expect("active jobs shouldn't be locked in deadlock handler") }); + thread::spawn(move || rustc_query_impl::deadlock(query_map, ®istry)); } #[cfg(parallel_compiler)] @@ -655,24 +650,6 @@ pub fn build_output_filenames( } } -#[cfg(not(target_os = "linux"))] -pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> { - std::fs::rename(src, dst) -} - -/// This function attempts to bypass the auto_da_alloc heuristic implemented by some filesystems -/// such as btrfs and ext4. When renaming over a file that already exists then they will "helpfully" -/// write back the source file before committing the rename in case a developer forgot some of -/// the fsyncs in the open/write/fsync(file)/rename/fsync(dir) dance for atomic file updates. -/// -/// To avoid triggering this heuristic we delete the destination first, if it exists. -/// The cost of an extra syscall is much lower than getting descheduled for the sync IO. -#[cfg(target_os = "linux")] -pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> { - let _ = std::fs::remove_file(dst); - std::fs::rename(src, dst) -} - /// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)" pub fn version_str() -> Option<&'static str> { option_env!("CFG_VERSION") diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index 97f9588ae1ef5..3da6bc14622a0 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -238,7 +238,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?; n_digits += 1; if n_digits > 6 { - // Stop updating value since we're sure that it's is incorrect already. + // Stop updating value since we're sure that it's incorrect already. continue; } let digit = digit as u32; diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index fab60b6f6096c..7c0f2c440d51d 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -22,3 +22,4 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_parse_format = { path = "../rustc_parse_format" } rustc_infer = { path = "../rustc_infer" } rustc_type_ir = { path = "../rustc_type_ir" } +rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index b33ab40eb39cb..121fefdc6207a 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -1,5 +1,5 @@ use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; @@ -120,31 +120,30 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { _ => bug!("array type coerced to something other than array or slice"), }; cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| { - let mut diag = lint.build(&format!( - "this method call resolves to `<&{} as IntoIterator>::into_iter` \ - (due to backwards compatibility), \ - but will resolve to <{} as IntoIterator>::into_iter in Rust 2021", - target, target, - )); + let mut diag = lint.build(fluent::lint::array_into_iter); + diag.set_arg("target", target); diag.span_suggestion( call.ident.span, - "use `.iter()` instead of `.into_iter()` to avoid ambiguity", + fluent::lint::use_iter_suggestion, "iter", Applicability::MachineApplicable, ); if self.for_expr_span == expr.span { diag.span_suggestion( receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - "or remove `.into_iter()` to iterate by value", + fluent::lint::remove_into_iter_suggestion, "", Applicability::MaybeIncorrect, ); } else if receiver_ty.is_array() { diag.multipart_suggestion( - "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value", + fluent::lint::use_explicit_into_iter_suggestion, vec![ (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()), - (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()), + ( + receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + ")".into(), + ), ], Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8266f1566c423..a0472f98d7204 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,14 +31,17 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString, MultiSpan}; +use rustc_errors::{ + fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, + LintDiagnosticBuilder, MultiSpan, +}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin}; use rustc_index::vec::Idx; -use rustc_middle::lint::{in_external_macro, LintDiagnosticBuilder}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::GenericArgKind; @@ -99,13 +102,12 @@ impl EarlyLintPass for WhileTrue { if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { if let ast::LitKind::Bool(true) = lit.kind { if !lit.span.from_expansion() { - let msg = "denote infinite loops with `loop { ... }`"; let condition_span = e.span.with_hi(cond.span.hi()); cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { - lint.build(msg) + lint.build(fluent::lint::builtin_while_true) .span_suggestion_short( condition_span, - "use `loop`", + fluent::lint::suggestion, format!( "{}loop", label.map_or_else(String::new, |label| format!( @@ -156,7 +158,7 @@ impl BoxPointers { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if leaf_ty.is_box() { cx.struct_span_lint(BOX_POINTERS, span, |lint| { - lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit(); + lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit(); }); } } @@ -257,26 +259,26 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results())) { cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| { - let mut err = lint - .build(&format!("the `{}:` in this pattern is redundant", ident)); let binding = match binding_annot { hir::BindingAnnotation::Unannotated => None, hir::BindingAnnotation::Mutable => Some("mut"), hir::BindingAnnotation::Ref => Some("ref"), hir::BindingAnnotation::RefMut => Some("ref mut"), }; - let ident = if let Some(binding) = binding { + let suggested_ident = if let Some(binding) = binding { format!("{} {}", binding, ident) } else { ident.to_string() }; - err.span_suggestion( - fieldpat.span, - "use shorthand field pattern", - ident, - Applicability::MachineApplicable, - ); - err.emit(); + lint.build(fluent::lint::builtin_non_shorthand_field_patterns) + .set_arg("ident", ident.clone()) + .span_suggestion( + fieldpat.span, + fluent::lint::suggestion, + suggested_ident, + Applicability::MachineApplicable, + ) + .emit(); }); } } @@ -327,26 +329,25 @@ impl UnsafeCode { cx.struct_span_lint(UNSAFE_CODE, span, decorate); } - fn report_overridden_symbol_name(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) { + fn report_overridden_symbol_name( + &self, + cx: &EarlyContext<'_>, + span: Span, + msg: DiagnosticMessage, + ) { self.report_unsafe(cx, span, |lint| { - lint.build(msg) - .note( - "the linker's behavior with multiple libraries exporting duplicate symbol \ - names is undefined and Rust cannot provide guarantees when you manually \ - override them", - ) - .emit(); + lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit(); }) } - fn report_overridden_symbol_section(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) { + fn report_overridden_symbol_section( + &self, + cx: &EarlyContext<'_>, + span: Span, + msg: DiagnosticMessage, + ) { self.report_unsafe(cx, span, |lint| { - lint.build(msg) - .note( - "the program's behavior with overridden link sections on items is unpredictable \ - and Rust cannot provide guarantees when you manually override them", - ) - .emit(); + lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit(); }) } } @@ -355,12 +356,7 @@ impl EarlyLintPass for UnsafeCode { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { if attr.has_name(sym::allow_internal_unsafe) { self.report_unsafe(cx, attr.span, |lint| { - lint.build( - "`allow_internal_unsafe` allows defining \ - macros using unsafe without triggering \ - the `unsafe_code` lint at their call site", - ) - .emit(); + lint.build(fluent::lint::builtin_allow_internal_unsafe).emit(); }); } } @@ -370,7 +366,7 @@ impl EarlyLintPass for UnsafeCode { // Don't warn about generated blocks; that'll just pollute the output. if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { self.report_unsafe(cx, blk.span, |lint| { - lint.build("usage of an `unsafe` block").emit(); + lint.build(fluent::lint::builtin_unsafe_block).emit(); }); } } @@ -380,12 +376,12 @@ impl EarlyLintPass for UnsafeCode { match it.kind { ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self .report_unsafe(cx, it.span, |lint| { - lint.build("declaration of an `unsafe` trait").emit(); + lint.build(fluent::lint::builtin_unsafe_trait).emit(); }), ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self .report_unsafe(cx, it.span, |lint| { - lint.build("implementation of an `unsafe` trait").emit(); + lint.build(fluent::lint::builtin_unsafe_impl).emit(); }), ast::ItemKind::Fn(..) => { @@ -393,7 +389,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a `no_mangle` function", + fluent::lint::builtin_no_mangle_fn, ); } @@ -401,7 +397,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a function with `export_name`", + fluent::lint::builtin_export_name_fn, ); } @@ -409,7 +405,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_section( cx, attr.span, - "declaration of a function with `link_section`", + fluent::lint::builtin_link_section_fn, ); } } @@ -419,7 +415,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a `no_mangle` static", + fluent::lint::builtin_no_mangle_static, ); } @@ -427,7 +423,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a static with `export_name`", + fluent::lint::builtin_export_name_static, ); } @@ -435,7 +431,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_section( cx, attr.span, - "declaration of a static with `link_section`", + fluent::lint::builtin_link_section_static, ); } } @@ -450,14 +446,14 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a `no_mangle` method", + fluent::lint::builtin_no_mangle_method, ); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a method with `export_name`", + fluent::lint::builtin_export_name_method, ); } } @@ -475,9 +471,9 @@ impl EarlyLintPass for UnsafeCode { { let msg = match ctxt { FnCtxt::Foreign => return, - FnCtxt::Free => "declaration of an `unsafe` function", - FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method", - FnCtxt::Assoc(_) => "implementation of an `unsafe` method", + FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn, + FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method, + FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method, }; self.report_unsafe(cx, span, |lint| { lint.build(msg).emit(); @@ -556,7 +552,6 @@ impl MissingDoc { &self, cx: &LateContext<'_>, def_id: LocalDefId, - sp: Span, article: &'static str, desc: &'static str, ) { @@ -583,13 +578,12 @@ impl MissingDoc { let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id)); let has_doc = attrs.iter().any(has_doc); if !has_doc { - cx.struct_span_lint( - MISSING_DOCS, - cx.tcx.sess.source_map().guess_head_span(sp), - |lint| { - lint.build(&format!("missing documentation for {} {}", article, desc)).emit(); - }, - ); + cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| { + lint.build(fluent::lint::builtin_missing_doc) + .set_arg("article", article) + .set_arg("desc", desc) + .emit(); + }); } } } @@ -612,13 +606,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'_>) { - self.check_missing_docs_attrs( - cx, - CRATE_DEF_ID, - cx.tcx.def_span(CRATE_DEF_ID), - "the", - "crate", - ); + self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate"); } fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { @@ -648,13 +636,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id()); - self.check_missing_docs_attrs(cx, it.def_id, it.span, article, desc); + self.check_missing_docs_attrs(cx, it.def_id, article, desc); } fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) { let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id()); - self.check_missing_docs_attrs(cx, trait_item.def_id, trait_item.span, article, desc); + self.check_missing_docs_attrs(cx, trait_item.def_id, article, desc); } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { @@ -682,23 +670,23 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); - self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc); + self.check_missing_docs_attrs(cx, impl_item.def_id, article, desc); } fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) { let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id()); - self.check_missing_docs_attrs(cx, foreign_item.def_id, foreign_item.span, article, desc); + self.check_missing_docs_attrs(cx, foreign_item.def_id, article, desc); } fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) { if !sf.is_positional() { let def_id = cx.tcx.hir().local_def_id(sf.hir_id); - self.check_missing_docs_attrs(cx, def_id, sf.span, "a", "struct field") + self.check_missing_docs_attrs(cx, def_id, "a", "struct field") } } fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) { - self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), v.span, "a", "variant"); + self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), "a", "variant"); } } @@ -783,11 +771,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { .is_ok() { cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { - lint.build( - "type could implement `Copy`; consider adding `impl \ - Copy`", - ) - .emit(); + lint.build(fluent::lint::builtin_missing_copy_impl).emit(); }) } } @@ -863,12 +847,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { if !self.impling_types.as_ref().unwrap().contains(&item.def_id) { cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| { - lint.build(&format!( - "type does not implement `{}`; consider adding `#[derive(Debug)]` \ - or a manual implementation", - cx.tcx.def_path_str(debug) - )) - .emit(); + lint.build(fluent::lint::builtin_missing_debug_impl) + .set_arg("debug", cx.tcx.def_path_str(debug)) + .emit(); }); } } @@ -946,18 +927,14 @@ impl EarlyLintPass for AnonymousParameters { ("<type>", Applicability::HasPlaceholders) }; - lint.build( - "anonymous parameters are deprecated and will be \ - removed in the next edition", - ) - .span_suggestion( - arg.pat.span, - "try naming the parameter or explicitly \ - ignoring it", - format!("_: {}", ty_snip), - appl, - ) - .emit(); + lint.build(fluent::lint::builtin_anonymous_params) + .span_suggestion( + arg.pat.span, + fluent::lint::suggestion, + format!("_: {}", ty_snip), + appl, + ) + .emit(); }) } } @@ -982,24 +959,6 @@ impl DeprecatedAttr { } } -fn lint_deprecated_attr( - cx: &EarlyContext<'_>, - attr: &ast::Attribute, - msg: &str, - suggestion: Option<&str>, -) { - cx.struct_span_lint(DEPRECATED, attr.span, |lint| { - lint.build(msg) - .span_suggestion_short( - attr.span, - suggestion.unwrap_or("remove this attribute"), - "", - Applicability::MachineApplicable, - ) - .emit(); - }) -} - impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { for BuiltinAttribute { name, gate, .. } in &self.depr_attrs { @@ -1011,17 +970,38 @@ impl EarlyLintPass for DeprecatedAttr { _, ) = gate { - let msg = - format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link); - lint_deprecated_attr(cx, attr, &msg, suggestion); + cx.struct_span_lint(DEPRECATED, attr.span, |lint| { + // FIXME(davidtwco) translatable deprecated attr + lint.build(fluent::lint::builtin_deprecated_attr_link) + .set_arg("name", name) + .set_arg("reason", reason) + .set_arg("link", link) + .span_suggestion_short( + attr.span, + suggestion.map(|s| s.into()).unwrap_or( + fluent::lint::builtin_deprecated_attr_default_suggestion, + ), + "", + Applicability::MachineApplicable, + ) + .emit(); + }); } return; } } if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { - let path_str = pprust::path_to_string(&attr.get_normal_item().path); - let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); - lint_deprecated_attr(cx, attr, &msg, None); + cx.struct_span_lint(DEPRECATED, attr.span, |lint| { + lint.build(fluent::lint::builtin_deprecated_attr_used) + .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path)) + .span_suggestion_short( + attr.span, + fluent::lint::builtin_deprecated_attr_default_suggestion, + "", + Applicability::MachineApplicable, + ) + .emit(); + }); } } } @@ -1049,17 +1029,15 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & if is_doc_comment || attr.has_name(sym::doc) { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { - let mut err = lint.build("unused doc comment"); - err.span_label( - node_span, - format!("rustdoc does not generate documentation for {}", node_kind), - ); + let mut err = lint.build(fluent::lint::builtin_unused_doc_comment); + err.set_arg("kind", node_kind); + err.span_label(node_span, fluent::lint::label); match attr.kind { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { - err.help("use `//` for a plain comment"); + err.help(fluent::lint::plain_help); } AttrKind::DocComment(CommentKind::Block, _) => { - err.help("use `/* */` for a plain comment"); + err.help(fluent::lint::block_help); } } err.emit(); @@ -1098,12 +1076,12 @@ impl EarlyLintPass for UnusedDocComment { } fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - warn_if_doc(cx, block.span, "block", &block.attrs()); + warn_if_doc(cx, block.span, "blocks", &block.attrs()); } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { if let ast::ItemKind::ForeignMod(_) = item.kind { - warn_if_doc(cx, item.span, "extern block", &item.attrs); + warn_if_doc(cx, item.span, "extern blocks", &item.attrs); } } } @@ -1178,10 +1156,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| { - lint.build("functions generic over types or consts must be mangled") + lint.build(fluent::lint::builtin_no_mangle_generic) .span_suggestion_short( no_mangle_attr.span, - "remove this attribute", + fluent::lint::suggestion, "", // Use of `#[no_mangle]` suggests FFI intent; correct // fix may be to monomorphize source by hand @@ -1205,8 +1183,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| { - let msg = "const items should never be `#[no_mangle]`"; - let mut err = lint.build(msg); + let mut err = lint.build(fluent::lint::builtin_const_no_mangle); // account for "pub const" (#45562) let start = cx @@ -1220,7 +1197,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); err.span_suggestion( const_span, - "try a static value", + fluent::lint::suggestion, "pub static", Applicability::MachineApplicable, ); @@ -1285,10 +1262,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { - let msg = "transmuting &T to &mut T is undefined behavior, \ - even if the reference is unused, consider instead using an UnsafeCell"; cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| { - lint.build(msg).emit(); + lint.build(fluent::lint::builtin_mutable_transmutes).emit(); }); } } @@ -1338,7 +1313,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { if let Some(items) = attr.meta_item_list() { for item in items { cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| { - lint.build("unstable feature").emit(); + lint.build(fluent::lint::builtin_unstable_features).emit(); }); } } @@ -1400,16 +1375,17 @@ impl UnreachablePub { } let def_span = cx.tcx.sess.source_map().guess_head_span(span); cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| { - let mut err = lint.build(&format!("unreachable `pub` {}", what)); + let mut err = lint.build(fluent::lint::builtin_unreachable_pub); + err.set_arg("what", what); err.span_suggestion( vis_span, - "consider restricting its visibility", + fluent::lint::suggestion, "pub(crate)", applicability, ); if exportable { - err.help("or consider exporting it for use by other crates"); + err.help(fluent::lint::help); } err.emit(); }); @@ -1513,11 +1489,7 @@ impl TypeAliasBounds { impl Visitor<'_> for WalkAssocTypes<'_> { fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help( - span, - "use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \ - associated types in type aliases", - ); + self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help); } intravisit::walk_qpath(self, qpath, id, span) } @@ -1561,11 +1533,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let mut suggested_changing_assoc_types = false; if !where_spans.is_empty() { cx.lint(TYPE_ALIAS_BOUNDS, |lint| { - let mut err = lint.build("where clauses are not enforced in type aliases"); + let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause); err.set_span(where_spans); err.span_suggestion( type_alias_generics.where_clause_span, - "the clause will not be checked when the type alias is used, and should be removed", + fluent::lint::suggestion, "", Applicability::MachineApplicable, ); @@ -1579,11 +1551,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { if !inline_spans.is_empty() { cx.lint(TYPE_ALIAS_BOUNDS, |lint| { - let mut err = - lint.build("bounds on generic parameters are not enforced in type aliases"); + let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds); err.set_span(inline_spans); err.multipart_suggestion( - "the bound will not be checked when the type alias is used, and should be removed", + fluent::lint::suggestion, inline_sugg, Applicability::MachineApplicable, ); @@ -1664,7 +1635,7 @@ declare_lint_pass!( impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - use rustc_middle::ty::fold::TypeFoldable; + use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::PredicateKind::*; if cx.tcx.features().trivial_bounds { @@ -1690,12 +1661,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { - lint.build(&format!( - "{} bound {} does not depend on any type \ - or lifetime parameters", - predicate_kind_name, predicate - )) - .emit(); + lint.build(fluent::lint::builtin_trivial_bounds) + .set_arg("predicate_kind_name", predicate_kind_name) + .set_arg("predicate", predicate) + .emit(); }); } } @@ -1796,8 +1765,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { }; if let Some((start, end, join)) = endpoints { - let msg = "`...` range patterns are deprecated"; - let suggestion = "use `..=` for an inclusive range"; + let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns; + let suggestion = fluent::lint::suggestion; if parenthesise { self.node_id = Some(pat.id); let end = expr_to_string(&end); @@ -1806,8 +1775,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { None => format!("&(..={})", end), }; if join.edition() >= Edition::Edition2021 { - let mut err = - rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); + let mut err = cx.sess().struct_span_err_with_code( + pat.span, + msg, + rustc_errors::error_code!(E0783), + ); err.span_suggestion( pat.span, suggestion, @@ -1830,8 +1802,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } else { let replace = "..="; if join.edition() >= Edition::Edition2021 { - let mut err = - rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); + let mut err = cx.sess().struct_span_err_with_code( + pat.span, + msg, + rustc_errors::error_code!(E0783), + ); err.span_suggestion_short( join, suggestion, @@ -1930,7 +1905,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) { cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| { - lint.build("cannot test inner items").emit(); + lint.build(fluent::lint::builtin_unnameable_test_items).emit(); }); } } @@ -2048,10 +2023,12 @@ impl KeywordIdents { } cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| { - lint.build(&format!("`{}` is a keyword in the {} edition", ident, next_edition)) + lint.build(fluent::lint::builtin_keyword_idents) + .set_arg("kw", ident.clone()) + .set_arg("next", next_edition) .span_suggestion( ident.span, - "you can use a raw identifier to stay compatible", + fluent::lint::suggestion, format!("r#{}", ident), Applicability::MachineApplicable, ) @@ -2301,13 +2278,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { if !lint_spans.is_empty() { cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| { - lint.build("outlives requirements can be inferred") + lint.build(fluent::lint::builtin_explicit_outlives) + .set_arg("count", bound_count) .multipart_suggestion( - if bound_count == 1 { - "remove this bound" - } else { - "remove these bounds" - }, + fluent::lint::suggestion, lint_spans .into_iter() .map(|span| (span, String::new())) @@ -2363,23 +2337,14 @@ impl EarlyLintPass for IncompleteFeatures { .filter(|(&name, _)| features.incomplete(name)) .for_each(|(&name, &span)| { cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| { - let mut builder = lint.build(&format!( - "the feature `{}` is incomplete and may not be safe to use \ - and/or cause compiler crashes", - name, - )); + let mut builder = lint.build(fluent::lint::builtin_incomplete_features); + builder.set_arg("name", name); if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) { - builder.note(&format!( - "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \ - for more information", - n, n, - )); + builder.set_arg("n", n); + builder.note(fluent::lint::note); } if HAS_MIN_FEATURES.contains(&name) { - builder.help(&format!( - "consider using `min_{}` instead, which is more stable and complete", - name, - )); + builder.help(fluent::lint::help); } builder.emit(); }) @@ -2620,6 +2585,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { if let Some((msg, span)) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) { + // FIXME(davidtwco): make translatable cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| { let mut err = lint.build(&format!( "the type `{}` does not permit {}", @@ -2996,23 +2962,19 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { let mut found_str = DiagnosticStyledString::new(); found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); - lint.build(&format!( - "`{}` redeclare{} with a different signature", - this_fi.ident.name, - if orig.get_name() == this_fi.ident.name { - "d".to_string() - } else { - format!("s `{}`", orig.get_name()) - } - )) + lint.build(if orig.get_name() == this_fi.ident.name { + fluent::lint::builtin_clashing_extern_same_name + } else { + fluent::lint::builtin_clashing_extern_diff_name + }) + .set_arg("this_fi", this_fi.ident.name) + .set_arg("orig", orig.get_name()) .span_label( get_relevant_span(orig_fi), - &format!("`{}` previously declared here", orig.get_name()), - ) - .span_label( - get_relevant_span(this_fi), - "this signature doesn't match the previous declaration", + fluent::lint::previous_decl_label, ) + .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label) + // FIXME(davidtwco): translatable expected/found .note_expected_found(&"", expected_str, &"", found_str) .emit(); }, @@ -3096,8 +3058,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if is_null_ptr(cx, expr_deref) { cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| { - let mut err = lint.build("dereferencing a null pointer"); - err.span_label(expr.span, "this code causes undefined behavior when executed"); + let mut err = lint.build(fluent::lint::builtin_deref_nullptr); + err.span_label(expr.span, fluent::lint::label); err.emit(); }); } @@ -3210,9 +3172,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { NAMED_ASM_LABELS, Some(target_spans), |diag| { - let mut err = - diag.build("avoid using named labels in inline assembly"); - err.emit(); + diag.build(fluent::lint::builtin_asm_labels).emit(); }, BuiltinLintDiagnostics::NamedAsmLabel( "only local labels of the form `<number>:` should be used in inline asm" diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index eeb66f2d73871..b4b472fe2df78 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -22,18 +22,19 @@ use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err}; -use rustc_errors::{Applicability, MultiSpan, SuggestionStyle}; +use rustc_errors::{ + Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle, +}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt}; -use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; use rustc_span::lev_distance::find_best_match_for_name; @@ -693,9 +694,8 @@ pub trait LintContext: Sized { } if let Some(span) = in_test_module { - let def_span = self.sess().source_map().guess_head_span(span); db.span_help( - span.shrink_to_lo().to(def_span), + self.sess().source_map().guess_head_span(span), "consider adding a `#[cfg(test)]` to the containing module", ); } @@ -856,6 +856,19 @@ pub trait LintContext: Sized { Applicability::MachineApplicable, ); }, + BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => { + db.span_label(named_arg, "this named argument is only referred to by position in formatting string"); + if let Some(positional_arg) = positional_arg { + let msg = format!("this formatting argument uses named argument `{}` by position", name); + db.span_label(positional_arg, msg); + db.span_suggestion_verbose( + positional_arg, + "use the named argument by name to avoid ambiguity", + format!("{{{}}}", name), + Applicability::MaybeIncorrect, + ); + } + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); @@ -871,6 +884,17 @@ pub trait LintContext: Sized { decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>), ); + /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, + /// typically generated by `#[derive(LintDiagnostic)]`). + fn emit_spanned_lint<S: Into<MultiSpan>>( + &self, + lint: &'static Lint, + span: S, + decorator: impl for<'a> DecorateLint<'a, ()>, + ) { + self.lookup(lint, Some(span), |diag| decorator.decorate_lint(diag)); + } + fn struct_span_lint<S: Into<MultiSpan>>( &self, lint: &'static Lint, @@ -879,6 +903,13 @@ pub trait LintContext: Sized { ) { self.lookup(lint, Some(span), decorate); } + + /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically + /// generated by `#[derive(LintDiagnostic)]`). + fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) { + self.lookup(lint, None as Option<Span>, |diag| decorator.decorate_lint(diag)); + } + /// Emit a lint at the appropriate level, with no associated span. fn lint( &self, @@ -887,6 +918,29 @@ pub trait LintContext: Sized { ) { self.lookup(lint, None as Option<Span>, decorate); } + + /// This returns the lint level for the given lint at the current location. + fn get_lint_level(&self, lint: &'static Lint) -> Level; + + /// This function can be used to manually fulfill an expectation. This can + /// be used for lints which contain several spans, and should be suppressed, + /// if either location was marked with an expectation. + /// + /// Note that this function should only be called for [`LintExpectationId`]s + /// retrieved from the current lint pass. Buffered or manually created ids can + /// cause ICEs. + fn fulfill_expectation(&self, expectation: LintExpectationId) { + // We need to make sure that submitted expectation ids are correctly fulfilled suppressed + // and stored between compilation sessions. To not manually do these steps, we simply create + // a dummy diagnostic and emit is as usual, which will be suppressed and stored like a normal + // expected lint diagnostic. + self.sess() + .struct_expect( + "this is a dummy diagnostic, to submit and store an expectation", + expectation, + ) + .emit(); + } } impl<'a> EarlyContext<'a> { @@ -934,6 +988,10 @@ impl LintContext for LateContext<'_> { None => self.tcx.struct_lint_node(lint, hir_id, decorate), } } + + fn get_lint_level(&self, lint: &'static Lint) -> Level { + self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs).0 + } } impl LintContext for EarlyContext<'_> { @@ -956,6 +1014,10 @@ impl LintContext for EarlyContext<'_> { ) { self.builder.struct_lint(lint, span.map(|s| s.into()), decorate) } + + fn get_lint_level(&self, lint: &'static Lint) -> Level { + self.builder.lint_level(lint).0 + } } impl<'tcx> LateContext<'tcx> { diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 5de35dc085601..b0a7a87fda4f7 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -154,6 +154,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> self.check_id(closure_id); } } + run_early_pass!(self, check_fn_post, fk, span, id); } @@ -218,7 +219,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> // Explicitly check for lints associated with 'closure_id', since // it does not have a corresponding AST node match e.kind { - ast::ExprKind::Closure(_, ast::Async::Yes { closure_id, .. }, ..) + ast::ExprKind::Closure(_, _, ast::Async::Yes { closure_id, .. }, ..) | ast::ExprKind::Async(_, closure_id, ..) => self.check_id(closure_id), _ => {} } @@ -416,7 +417,7 @@ pub fn check_ast_node<'a>( let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect(); let mut buffered = lint_buffer.unwrap_or_default(); - if sess.opts.debugging_opts.no_interleave_lints { + if sess.opts.unstable_opts.no_interleave_lints { for (i, pass) in passes.iter_mut().enumerate() { buffered = sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| { diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index c5e15a88fdf1c..f41ee6404992d 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -1,6 +1,7 @@ use crate::{context::LintContext, LateContext, LateLintPass}; +use rustc_errors::fluent; use rustc_hir as hir; -use rustc_middle::ty::{fold::TypeFoldable, Ty}; +use rustc_middle::ty::{visit::TypeVisitable, Ty}; use rustc_span::{symbol::sym, Span}; declare_lint! { @@ -51,19 +52,9 @@ fn enforce_mem_discriminant( if is_non_enum(ty_param) { cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| { builder - .build( - "the return value of `mem::discriminant` is \ - unspecified when called with a non-enum type", - ) - .span_note( - args_span, - &format!( - "the argument to `discriminant` should be a \ - reference to an enum, but it was passed \ - a reference to a `{}`, which is not an enum.", - ty_param, - ), - ) + .build(fluent::lint::enum_intrinsics_mem_discriminant) + .set_arg("ty_param", ty_param) + .span_note(args_span, fluent::lint::note) .emit(); }); } @@ -74,16 +65,9 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp if is_non_enum(ty_param) { cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| { builder - .build( - "the return value of `mem::variant_count` is \ - unspecified when called with a non-enum type", - ) - .note(&format!( - "the type parameter of `variant_count` should \ - be an enum, but it was instantiated with \ - the type `{}`, which is not an enum.", - ty_param, - )) + .build(fluent::lint::enum_intrinsics_mem_variant) + .set_arg("ty_param", ty_param) + .note(fluent::lint::note) .emit(); }); } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 95e3125045db4..699e81543188f 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,4 +1,5 @@ use crate::builtin; +use rustc_errors::fluent; use rustc_hir::HirId; use rustc_middle::ty::query::Providers; use rustc_middle::{lint::LintExpectation, ty::TyCtxt}; @@ -43,13 +44,13 @@ fn emit_unfulfilled_expectation_lint( hir_id, expectation.emission_span, |diag| { - let mut diag = diag.build("this lint expectation is unfulfilled"); + let mut diag = diag.build(fluent::lint::expectation); if let Some(rationale) = expectation.reason { diag.note(rationale.as_str()); } if expectation.is_unfulfilled_lint_expectations { - diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message"); + diag.note(fluent::lint::note); } diag.emit(); diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index fc99d759a03f5..fe2712525eea5 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -1,7 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; use rustc_ast as ast; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::{fluent, Applicability, SuggestionStyle}; use rustc_span::{BytePos, Span, Symbol}; declare_lint! { @@ -61,41 +61,25 @@ impl HiddenUnicodeCodepoints { .collect(); cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| { - let mut err = lint.build(&format!( - "unicode codepoint changing visible direction of text present in {}", - label - )); - let (an, s) = match spans.len() { - 1 => ("an ", ""), - _ => ("", "s"), - }; - err.span_label( - span, - &format!( - "this {} contains {}invisible unicode text flow control codepoint{}", - label, an, s, - ), - ); + let mut err = lint.build(fluent::lint::hidden_unicode_codepoints); + err.set_arg("label", label); + err.set_arg("count", spans.len()); + err.span_label(span, fluent::lint::label); + err.note(fluent::lint::note); if point_at_inner_spans { for (c, span) in &spans { err.span_label(*span, format!("{:?}", c)); } } - err.note( - "these kind of unicode codepoints change the way text flows on applications that \ - support them, but can cause confusion because they change the order of \ - characters on the screen", - ); if point_at_inner_spans && !spans.is_empty() { err.multipart_suggestion_with_style( - "if their presence wasn't intentional, you can remove them", + fluent::lint::suggestion_remove, spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); err.multipart_suggestion( - "if you want to keep them but make them visible in your source code, you can \ - escape them", + fluent::lint::suggestion_escape, spans .into_iter() .map(|(c, span)| { @@ -109,16 +93,16 @@ impl HiddenUnicodeCodepoints { // FIXME: in other suggestions we've reversed the inner spans of doc comments. We // should do the same here to provide the same good suggestions as we do for // literals above. - err.note("if their presence wasn't intentional, you can remove them"); - err.note(&format!( - "if you want to keep them but make them visible in your source code, you can \ - escape them: {}", + err.set_arg( + "escaped", spans .into_iter() - .map(|(c, _)| { format!("{:?}", c) }) + .map(|(c, _)| format!("{:?}", c)) .collect::<Vec<String>>() .join(", "), - )); + ); + err.note(fluent::lint::suggestion_remove); + err.note(fluent::lint::no_suggestion_note_escape); } err.emit(); }); diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index fadb1c8793398..738f475983e9b 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir::def::Res; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; @@ -36,13 +36,10 @@ impl LateLintPass<'_> for DefaultHashTypes { _ => return, }; cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { - let msg = format!( - "prefer `{}` over `{}`, it has better performance", - replace, - cx.tcx.item_name(def_id) - ); - lint.build(&msg) - .note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace)) + lint.build(fluent::lint::default_hash_types) + .set_arg("preferred", replace) + .set_arg("used", cx.tcx.item_name(def_id)) + .note(fluent::lint::note) .emit(); }); } @@ -99,12 +96,9 @@ impl LateLintPass<'_> for QueryStability { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| { - let msg = format!( - "using `{}` can result in unstable query results", - cx.tcx.item_name(def_id) - ); - lint.build(&msg) - .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale") + lint.build(fluent::lint::query_instability) + .set_arg("query", cx.tcx.item_name(def_id)) + .note(fluent::lint::note) .emit(); }) } @@ -146,10 +140,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() ); cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { - lint.build("usage of `ty::TyKind::<kind>`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( span, - "try using `ty::<kind>` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -175,10 +169,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { - lint.build("usage of `ty::TyKind::<kind>`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( path.span, - "try using `ty::<kind>` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -193,10 +187,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { - lint.build("usage of `ty::TyKind::<kind>`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( path.span, - "try using `ty::<kind>` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -213,10 +207,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { - lint.build("usage of `ty::TyKind::<kind>`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( path.span, - "try using `ty::<kind>` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -226,15 +220,16 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } _ => {} } - lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit(); + lint.build(fluent::lint::tykind).help(fluent::lint::help).emit(); }) } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { if path.segments.len() > 1 { cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| { - lint.build(&format!("usage of qualified `ty::{}`", t)) + lint.build(fluent::lint::ty_qualified) + .set_arg("ty", t.clone()) .span_suggestion( path.span, - "try importing it and using it unqualified", + fluent::lint::suggestion, t, // The import probably needs to be changed Applicability::MaybeIncorrect, @@ -330,8 +325,8 @@ impl EarlyLintPass for LintPassImpl { LINT_PASS_IMPL_WITHOUT_MACRO, lint_pass.path.span, |lint| { - lint.build("implementing `LintPass` by hand") - .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") + lint.build(fluent::lint::lintpass_by_hand) + .help(fluent::lint::help) .emit(); }, ) @@ -371,13 +366,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { return; } cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { - lint.build(&format!( - "Found non-existing keyword `{}` used in \ - `#[doc(keyword = \"...\")]`", - v, - )) - .help("only existing keywords are allowed in core/std") - .emit(); + lint.build(fluent::lint::non_existant_doc_keyword) + .set_arg("keyword", v) + .help(fluent::lint::help) + .emit(); }); } } @@ -406,9 +398,12 @@ impl LateLintPass<'_> for Diagnostics { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Some((span, def_id, substs)) = typeck_results_of_method_fn(cx, expr) else { return }; debug!(?span, ?def_id, ?substs); - if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) && - !cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_diagnostics) - { + let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) + .ok() + .and_then(|inst| inst) + .map(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics)) + .unwrap_or(false); + if !has_attr { return; } @@ -419,7 +414,7 @@ impl LateLintPass<'_> for Diagnostics { let Impl { of_trait: Some(of_trait), .. } = impl_ && let Some(def_id) = of_trait.trait_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(def_id) && - matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic) + matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic | sym::DecorateLint) { found_impl = true; break; @@ -428,8 +423,7 @@ impl LateLintPass<'_> for Diagnostics { debug!(?found_impl); if !found_impl { cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| { - lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls") - .emit(); + lint.build(fluent::lint::diag_out_of_impl).emit(); }) } @@ -447,7 +441,7 @@ impl LateLintPass<'_> for Diagnostics { debug!(?found_diagnostic_message); if !found_diagnostic_message { cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| { - lint.build("diagnostics should be created using translatable messages").emit(); + lint.build(fluent::lint::untranslatable_diag).emit(); }) } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index c1d8d76c975d8..afb18451cf398 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -34,7 +34,7 @@ use tracing::debug; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. -pub(crate) fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore { +pub fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore { let store: &dyn Any = &*tcx.lint_store; store.downcast_ref().unwrap() } @@ -402,7 +402,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( module_def_id: LocalDefId, builtin_lints: T, ) { - if tcx.sess.opts.debugging_opts.no_interleave_lints { + if tcx.sess.opts.unstable_opts.no_interleave_lints { // These passes runs in late_lint_crate with -Z no_interleave_lints return; } @@ -448,7 +448,7 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>(); - if !tcx.sess.opts.debugging_opts.no_interleave_lints { + if !tcx.sess.opts.unstable_opts.no_interleave_lints { if !passes.is_empty() { late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] }); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 4773feded12fa..00e96f20d1aaa 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -3,13 +3,13 @@ use crate::late::unerased_lint_store; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - struct_lint_level, LevelAndSource, LintDiagnosticBuilder, LintExpectation, LintLevelMap, - LintLevelSets, LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE, + struct_lint_level, LevelAndSource, LintExpectation, LintLevelMap, LintLevelSets, + LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -521,7 +521,7 @@ impl<'s> LintLevelsBuilder<'s> { src, Some(sp.into()), |lint| { - let mut err = lint.build(&msg); + let mut err = lint.build(msg); if let Some(new_name) = &renamed { err.span_suggestion( sp, @@ -548,7 +548,7 @@ impl<'s> LintLevelsBuilder<'s> { } else { name.to_string() }; - let mut db = lint.build(&format!("unknown lint: `{}`", name)); + let mut db = lint.build(format!("unknown lint: `{}`", name)); if let Some(suggestion) = suggestion { db.span_suggestion( sp, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c1255ae5056ac..8726d36498bed 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,7 +33,7 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iter_order_by)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] @@ -99,7 +99,7 @@ pub use builtin::SoftLints; pub use context::{CheckLintNameResult, FindLintError, LintStore}; pub use context::{EarlyContext, LateContext, LintContext}; pub use early::{check_ast_node, EarlyCheckNode}; -pub use late::check_crate; +pub use late::{check_crate, unerased_lint_store}; pub use passes::{EarlyLintPass, LateLintPass}; pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index b6a45676a3093..ff5a01749c19e 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -1,6 +1,7 @@ use crate::LateContext; use crate::LateLintPass; use crate::LintContext; +use rustc_errors::fluent; use rustc_hir::{Expr, ExprKind, PathSegment}; use rustc_middle::ty; use rustc_span::{symbol::sym, ExpnKind, Span}; @@ -88,16 +89,12 @@ fn lint_cstring_as_ptr( if let ty::Adt(adt, _) = substs.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| { - let mut diag = diag - .build("getting the inner pointer of a temporary `CString`"); - diag.span_label(as_ptr_span, "this pointer will be invalid"); - diag.span_label( - unwrap.span, - "this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime", - ); - diag.note("pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned"); - diag.help("for more information, see https://doc.rust-lang.org/reference/destructors.html"); - diag.emit(); + diag.build(fluent::lint::cstring_ptr) + .span_label(as_ptr_span, fluent::lint::as_ptr_label) + .span_label(unwrap.span, fluent::lint::unwrap_label) + .note(fluent::lint::note) + .help(fluent::lint::help) + .emit(); }); } } diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 6182d2b10ed5b..764003e61a6df 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -1,6 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::fluent; use rustc_span::symbol::Symbol; declare_lint! { @@ -180,13 +181,13 @@ impl EarlyLintPass for NonAsciiIdents { } has_non_ascii_idents = true; cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| { - lint.build("identifier contains non-ASCII characters").emit(); + lint.build(fluent::lint::identifier_non_ascii_char).emit(); }); if check_uncommon_codepoints && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) { cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| { - lint.build("identifier contains uncommon Unicode codepoints").emit(); + lint.build(fluent::lint::identifier_uncommon_codepoints).emit(); }) } } @@ -216,15 +217,11 @@ impl EarlyLintPass for NonAsciiIdents { .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| { if !*existing_is_ascii || !is_ascii { cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { - lint.build(&format!( - "identifier pair considered confusable between `{}` and `{}`", - existing_symbol, symbol - )) - .span_label( - *existing_span, - "this is where the previous identifier occurred", - ) - .emit(); + lint.build(fluent::lint::confusable_identifier_pair) + .set_arg("existing_sym", *existing_symbol) + .set_arg("sym", symbol) + .span_label(*existing_span, fluent::lint::label) + .emit(); }); } if *existing_is_ascii && !is_ascii { @@ -326,18 +323,20 @@ impl EarlyLintPass for NonAsciiIdents { for ((sp, ch_list), script_set) in lint_reports { cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { - let message = format!( - "the usage of Script Group `{}` in this crate consists solely of mixed script confusables", - script_set); - let mut note = "the usage includes ".to_string(); + let mut includes = String::new(); for (idx, ch) in ch_list.into_iter().enumerate() { if idx != 0 { - note += ", "; + includes += ", "; } let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); - note += &char_info; + includes += &char_info; } - lint.build(&message).note(¬e).note("please recheck to make sure their usages are indeed what you want").emit(); + lint.build(fluent::lint::mixed_script_confusables) + .set_arg("set", script_set.to_string()) + .set_arg("includes", includes) + .note(fluent::lint::includes_note) + .note(fluent::lint::note) + .emit(); }); } } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 4e7aeca9ce1d5..cdad2d2e8f93e 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -1,6 +1,6 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_errors::{pluralize, Applicability}; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::lint::in_external_macro; @@ -120,9 +120,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| { - let mut l = lint.build("panic message is not a string literal"); - l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol)); - l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>"); + let mut l = lint.build(fluent::lint::non_fmt_panic); + l.set_arg("name", symbol); + l.note(fluent::lint::note); + l.note(fluent::lint::more_info_note); if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. l.emit(); @@ -130,10 +131,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. - l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str()); + l.note(fluent::lint::supports_fmt_note); if let Some((open, close, _)) = find_delimiters(cx, arg_span) { l.multipart_suggestion( - "remove the `format!(..)` macro call", + fluent::lint::supports_fmt_suggestion, vec![ (arg_span.until(open.shrink_to_hi()), "".into()), (close.until(arg_span.shrink_to_hi()), "".into()), @@ -153,12 +154,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ); let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| { - let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { - infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() - }) == Some(true); - let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { - infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() - }) == Some(true); + let display = is_str + || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { + infcx + .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) + .may_apply() + }) == Some(true); + let debug = !display + && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { + infcx + .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) + .may_apply() + }) == Some(true); (display, debug) }); @@ -175,17 +182,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_display { l.span_suggestion_verbose( arg_span.shrink_to_lo(), - "add a \"{}\" format string to Display the message", + fluent::lint::display_suggestion, "\"{}\", ", fmt_applicability, ); } else if suggest_debug { + l.set_arg("ty", ty); l.span_suggestion_verbose( arg_span.shrink_to_lo(), - &format!( - "add a \"{{:?}}\" format string to use the Debug implementation of `{}`", - ty, - ), + fluent::lint::debug_suggestion, "\"{:?}\", ", fmt_applicability, ); @@ -193,15 +198,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_panic_any { if let Some((open, close, del)) = find_delimiters(cx, span) { + l.set_arg("already_suggested", suggest_display || suggest_debug); l.multipart_suggestion( - &format!( - "{}use std::panic::panic_any instead", - if suggest_display || suggest_debug { - "or " - } else { - "" - }, - ), + fluent::lint::panic_suggestion, if del == '(' { vec![(span.until(open), "std::panic::panic_any".into())] } else { @@ -260,21 +259,19 @@ fn check_panic_str<'tcx>( .collect(), }; cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| { - let mut l = lint.build(match n_arguments { - 1 => "panic message contains an unused formatting placeholder", - _ => "panic message contains unused formatting placeholders", - }); - l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021"); + let mut l = lint.build(fluent::lint::non_fmt_panic_unused); + l.set_arg("count", n_arguments); + l.note(fluent::lint::note); if is_arg_inside_call(arg.span, span) { l.span_suggestion( arg.span.shrink_to_hi(), - &format!("add the missing argument{}", pluralize!(n_arguments)), + fluent::lint::add_args_suggestion, ", ...", Applicability::HasPlaceholders, ); l.span_suggestion( arg.span.shrink_to_lo(), - "or add a \"{}\" format string to use the message literally", + fluent::lint::add_fmt_suggestion, "\"{}\", ", Applicability::MachineApplicable, ); @@ -289,17 +286,15 @@ fn check_panic_str<'tcx>( .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })) .collect() }); - let msg = match &brace_spans { - Some(v) if v.len() == 1 => "panic message contains a brace", - _ => "panic message contains braces", - }; + let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2); cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| { - let mut l = lint.build(msg); - l.note("this message is not used as a format string, but will be in Rust 2021"); + let mut l = lint.build(fluent::lint::non_fmt_panic_braces); + l.set_arg("count", count); + l.note(fluent::lint::note); if is_arg_inside_call(arg.span, span) { l.span_suggestion( arg.span.shrink_to_lo(), - "add a \"{}\" format string to use the message literally", + fluent::lint::suggestion, "\"{}\", ", Applicability::MachineApplicable, ); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index e1507d0fbb48f..33ac2ed02aa00 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,7 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; @@ -137,22 +137,23 @@ impl NonCamelCaseTypes { if !is_camel_case(name) { cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| { - let msg = format!("{} `{}` should have an upper camel case name", sort, name); - let mut err = lint.build(&msg); + let mut err = lint.build(fluent::lint::non_camel_case_type); let cc = to_camel_case(name); // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". if *name != cc { err.span_suggestion( ident.span, - "convert the identifier to upper camel case", + fluent::lint::suggestion, to_camel_case(name), Applicability::MaybeIncorrect, ); } else { - err.span_label(ident.span, "should have an UpperCamelCase name"); + err.span_label(ident.span, fluent::lint::label); } + err.set_arg("sort", sort); + err.set_arg("name", name); err.emit(); }) } @@ -281,11 +282,10 @@ impl NonSnakeCase { if !is_snake_case(name) { cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| { let sc = NonSnakeCase::to_snake_case(name); - let msg = format!("{} `{}` should have a snake case name", sort, name); - let mut err = lint.build(&msg); + let mut err = lint.build(fluent::lint::non_snake_case); // We cannot provide meaningful suggestions // if the characters are in the category of "Uppercase Letter". - if *name != sc { + if name != sc { // We have a valid span in almost all cases, but we don't have one when linting a crate // name provided via the command line. if !ident.span.is_dummy() { @@ -295,13 +295,13 @@ impl NonSnakeCase { // Instead, recommend renaming the identifier entirely or, if permitted, // escaping it to create a raw identifier. if sc_ident.name.can_be_raw() { - ("rename the identifier or convert it to a snake case raw identifier", sc_ident.to_string()) + (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string()) } else { - err.note(&format!("`{}` cannot be used as a raw identifier", sc)); - ("rename the identifier", String::new()) + err.note(fluent::lint::cannot_convert_note); + (fluent::lint::rename_suggestion, String::new()) } } else { - ("convert the identifier to snake case", sc) + (fluent::lint::convert_suggestion, sc.clone()) }; err.span_suggestion( @@ -311,12 +311,15 @@ impl NonSnakeCase { Applicability::MaybeIncorrect, ); } else { - err.help(&format!("convert the identifier to snake case: `{}`", sc)); + err.help(fluent::lint::help); } } else { - err.span_label(ident.span, "should have a snake_case name"); + err.span_label(ident.span, fluent::lint::label); } + err.set_arg("sort", sort); + err.set_arg("name", name); + err.set_arg("sc", sc); err.emit(); }); } @@ -488,21 +491,22 @@ impl NonUpperCaseGlobals { if name.chars().any(|c| c.is_lowercase()) { cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| { let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); - let mut err = - lint.build(&format!("{} `{}` should have an upper case name", sort, name)); + let mut err = lint.build(fluent::lint::non_upper_case_global); // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". if *name != uc { err.span_suggestion( ident.span, - "convert the identifier to upper case", + fluent::lint::suggestion, uc, Applicability::MaybeIncorrect, ); } else { - err.span_label(ident.span, "should have an UPPER_CASE name"); + err.span_label(ident.span, fluent::lint::label); } + err.set_arg("sort", sort); + err.set_arg("name", name); err.emit(); }) } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 675bee738a672..11a752ff09705 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -1,7 +1,8 @@ use crate::context::LintContext; -use crate::rustc_middle::ty::TypeFoldable; +use crate::rustc_middle::ty::TypeVisitable; use crate::LateContext; use crate::LateLintPass; +use rustc_errors::fluent; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; @@ -80,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { ) { return; } - let method = &call.ident.name; let receiver = &elements[0]; let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); @@ -90,19 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { return; } let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as \ - the type returned from `{}`, so the method call does not do \ - anything and can be removed", - receiver_ty, method, method, - ); - let span = expr_span.with_lo(receiver.span.hi()); cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let method = &call.ident.name; - let message = - format!("call to `.{}()` on a reference in this situation does nothing", &method,); - lint.build(&message).span_label(span, "unnecessary method call").note(¬e).emit(); + lint.build(fluent::lint::noop_method_call) + .set_arg("method", call.ident.name) + .set_arg("receiver_ty", receiver_ty) + .span_label(span, fluent::lint::label) + .note(fluent::lint::note) + .emit(); }); } } diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 2c8b41d721403..af5e5faf1f568 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -1,5 +1,5 @@ use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; @@ -30,10 +30,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } if let Some(t) = path_for_pass_by_value(cx, &inner_ty) { cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| { - lint.build(&format!("passing `{}` by reference", t)) + lint.build(fluent::lint::pass_by_value) + .set_arg("ty", t.clone()) .span_suggestion( ty.span, - "try passing by value", + fluent::lint::suggestion, t, // Changing type of function argument Applicability::MaybeIncorrect, diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index f06a8b8f4b0c3..26f41345383f9 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -1,6 +1,6 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::{Block, StmtKind}; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_span::Span; declare_lint! { @@ -49,12 +49,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo } cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { - let (msg, rem) = if multiple { - ("unnecessary trailing semicolons", "remove these semicolons") - } else { - ("unnecessary trailing semicolon", "remove this semicolon") - }; - lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit(); + lint.build(fluent::lint::redundant_semicolons) + .set_arg("multiple", multiple) + .span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect) + .emit(); }); } } diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 81d308ee34702..df1587c5948f5 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -1,6 +1,7 @@ use crate::LateContext; use crate::LateLintPass; use crate::LintContext; +use rustc_errors::fluent; use rustc_hir as hir; use rustc_span::symbol::sym; @@ -103,13 +104,10 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - let msg = format!( - "bounds on `{}` are most likely incorrect, consider instead \ - using `{}` to detect whether a type can be trivially dropped", - predicate, - cx.tcx.def_path_str(needs_drop) - ); - lint.build(&msg).emit(); + lint.build(fluent::lint::drop_trait_constraints) + .set_arg("predicate", predicate) + .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) + .emit(); }); } } @@ -126,12 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - let msg = format!( - "types that do not implement `Drop` can still have drop glue, consider \ - instead using `{}` to detect whether a type is trivially dropped", - cx.tcx.def_path_str(needs_drop) - ); - lint.build(&msg).emit(); + lint.build(fluent::lint::drop_glue) + .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) + .emit(); }); } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 2a2dc6822ce16..aca481df2e113 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -2,13 +2,13 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability, DiagnosticMessage}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; +use rustc_macros::LintDiagnostic; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -140,7 +140,8 @@ fn lint_overflowing_range_endpoint<'tcx>( // overflowing and only by 1. if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| { - let mut err = lint.build(&format!("range endpoint is out of range for `{}`", ty)); + let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); + err.set_arg("ty", ty); if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { use ast::{LitIntType, LitKind}; // We need to preserve the literal's suffix, @@ -154,7 +155,7 @@ fn lint_overflowing_range_endpoint<'tcx>( let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); err.span_suggestion( parent_expr.span, - "use an inclusive range instead", + fluent::lint::suggestion, suggestion, Applicability::MachineApplicable, ); @@ -230,38 +231,35 @@ fn report_bin_hex_error( (t.name_str(), actually.to_string()) } }; - let mut err = lint.build(&format!("literal out of range for `{}`", t)); + let mut err = lint.build(fluent::lint::overflowing_bin_hex); if negative { // If the value is negative, // emits a note about the value itself, apart from the literal. - err.note(&format!( - "the literal `{}` (decimal `{}`) does not fit into \ - the type `{}`", - repr_str, val, t - )); - err.note(&format!("and the value `-{}` will become `{}{}`", repr_str, actually, t)); + err.note(fluent::lint::negative_note); + err.note(fluent::lint::negative_becomes_note); } else { - err.note(&format!( - "the literal `{}` (decimal `{}`) does not fit into \ - the type `{}` and will become `{}{}`", - repr_str, val, t, actually, t - )); + err.note(fluent::lint::positive_note); } if let Some(sugg_ty) = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative) { + err.set_arg("suggestion_ty", sugg_ty); if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { let (sans_suffix, _) = repr_str.split_at(pos); err.span_suggestion( expr.span, - &format!("consider using the type `{}` instead", sugg_ty), + fluent::lint::suggestion, format!("{}{}", sans_suffix, sugg_ty), Applicability::MachineApplicable, ); } else { - err.help(&format!("consider using the type `{}` instead", sugg_ty)); + err.help(fluent::lint::help); } } + err.set_arg("ty", t); + err.set_arg("lit", repr_str); + err.set_arg("dec", val); + err.set_arg("actually", actually); err.emit(); }); } @@ -354,21 +352,23 @@ fn lint_int_literal<'tcx>( } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str())); - err.note(&format!( - "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + let mut err = lint.build(fluent::lint::overflowing_int); + err.set_arg("ty", t.name_str()); + err.set_arg( + "lit", cx.sess() .source_map() .span_to_snippet(lit.span) .expect("must get snippet from literal"), - t.name_str(), - min, - max, - )); + ); + err.set_arg("min", min); + err.set_arg("max", max); + err.note(fluent::lint::note); if let Some(sugg_ty) = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) { - err.help(&format!("consider using the type `{}` instead", sugg_ty)); + err.set_arg("suggestion_ty", sugg_ty); + err.help(fluent::lint::help); } err.emit(); }); @@ -396,10 +396,10 @@ fn lint_uint_literal<'tcx>( hir::ExprKind::Cast(..) => { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| { - lint.build("only `u8` can be cast into `char`") + lint.build(fluent::lint::only_cast_u8_to_char) .span_suggestion( par_e.span, - "use a `char` literal instead", + fluent::lint::suggestion, format!("'\\u{{{:X}}}'", lit_val), Applicability::MachineApplicable, ) @@ -430,17 +430,18 @@ fn lint_uint_literal<'tcx>( return; } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())) - .note(&format!( - "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + lint.build(fluent::lint::overflowing_uint) + .set_arg("ty", t.name_str()) + .set_arg( + "lit", cx.sess() .source_map() .span_to_snippet(lit.span) .expect("must get snippet from literal"), - t.name_str(), - min, - max, - )) + ) + .set_arg("min", min) + .set_arg("max", max) + .note(fluent::lint::note) .emit(); }); } @@ -472,16 +473,16 @@ fn lint_literal<'tcx>( }; if is_infinite == Ok(true) { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())) - .note(&format!( - "the literal `{}` does not fit into the type `{}` and will be converted to `{}::INFINITY`", + lint.build(fluent::lint::overflowing_literal) + .set_arg("ty", t.name_str()) + .set_arg( + "lit", cx.sess() .source_map() .span_to_snippet(lit.span) .expect("must get snippet from literal"), - t.name_str(), - t.name_str(), - )) + ) + .note(fluent::lint::note) .emit(); }); } @@ -502,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { hir::ExprKind::Binary(binop, ref l, ref r) => { if is_comparison(binop) && !check_limits(cx, binop, &l, &r) { cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| { - lint.build("comparison is useless due to type limits").emit(); + lint.build(fluent::lint::unused_comparisons).emit(); }); } } @@ -664,7 +665,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> { enum FfiResult<'tcx> { FfiSafe, FfiPhantom(Ty<'tcx>), - FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> }, + FfiUnsafe { ty: Ty<'tcx>, reason: DiagnosticMessage, help: Option<DiagnosticMessage> }, } pub(crate) fn nonnull_optimization_guaranteed<'tcx>( @@ -702,9 +703,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi return true; } - // Types with a `#[repr(no_niche)]` attribute have their niche hidden. - // The attribute is used by the UnsafeCell for example (the only use so far). - if def.repr().hide_niche() { + // `UnsafeCell` has its niche hidden. + if def.is_unsafe_cell() { return false; } @@ -824,8 +824,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.emit_ffi_unsafe_type_lint( ty, sp, - "passing raw arrays by value is not FFI-safe", - Some("consider passing a pointer to the array"), + fluent::lint::improper_ctypes_array_reason, + Some(fluent::lint::improper_ctypes_array_help), ); true } else { @@ -868,11 +868,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { // All fields are ZSTs; this means that the type should behave // like (), which is FFI-unsafe - FfiUnsafe { - ty, - reason: "this struct contains only zero-sized fields".into(), - help: None, - } + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None } } } else { // We can't completely trust repr(C) markings; make sure the fields are @@ -886,7 +882,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiPhantom(..) if def.is_enum() => { return FfiUnsafe { ty, - reason: "this enum contains a PhantomData field".into(), + reason: fluent::lint::improper_ctypes_enum_phantomdata, help: None, }; } @@ -922,7 +918,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { return FfiUnsafe { ty, - reason: "box cannot be represented as a single pointer".to_string(), + reason: fluent::lint::improper_ctypes_box, help: None, }; } @@ -932,17 +928,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match def.adt_kind() { AdtKind::Struct | AdtKind::Union => { - let kind = if def.is_struct() { "struct" } else { "union" }; - if !def.repr().c() && !def.repr().transparent() { return FfiUnsafe { ty, - reason: format!("this {} has unspecified layout", kind), - help: Some(format!( - "consider adding a `#[repr(C)]` or \ - `#[repr(transparent)]` attribute to this {}", - kind - )), + reason: if def.is_struct() { + fluent::lint::improper_ctypes_struct_layout_reason + } else { + fluent::lint::improper_ctypes_union_layout_reason + }, + help: if def.is_struct() { + Some(fluent::lint::improper_ctypes_struct_layout_help) + } else { + Some(fluent::lint::improper_ctypes_union_layout_help) + }, }; } @@ -951,7 +949,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !def.did().is_local() { return FfiUnsafe { ty, - reason: format!("this {} is non-exhaustive", kind), + reason: if def.is_struct() { + fluent::lint::improper_ctypes_struct_non_exhaustive + } else { + fluent::lint::improper_ctypes_union_non_exhaustive + }, help: None, }; } @@ -959,8 +961,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { ty, - reason: format!("this {} has no fields", kind), - help: Some(format!("consider adding a member to this {}", kind)), + reason: if def.is_struct() { + fluent::lint::improper_ctypes_struct_fieldless_reason + } else { + fluent::lint::improper_ctypes_union_fieldless_reason + }, + help: if def.is_struct() { + Some(fluent::lint::improper_ctypes_struct_fieldless_help) + } else { + Some(fluent::lint::improper_ctypes_union_fieldless_help) + }, }; } @@ -980,13 +990,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if repr_nullable_ptr(self.cx, ty, self.mode).is_none() { return FfiUnsafe { ty, - reason: "enum has no representation hint".into(), - help: Some( - "consider adding a `#[repr(C)]`, \ - `#[repr(transparent)]`, or integer `#[repr(...)]` \ - attribute to this enum" - .into(), - ), + reason: fluent::lint::improper_ctypes_enum_repr_reason, + help: Some(fluent::lint::improper_ctypes_enum_repr_help), }; } } @@ -994,7 +999,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.is_variant_list_non_exhaustive() && !def.did().is_local() { return FfiUnsafe { ty, - reason: "this enum is non-exhaustive".into(), + reason: fluent::lint::improper_ctypes_non_exhaustive, help: None, }; } @@ -1005,7 +1010,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !variant.def_id.is_local() { return FfiUnsafe { ty, - reason: "this enum has non-exhaustive variants".into(), + reason: fluent::lint::improper_ctypes_non_exhaustive_variant, help: None, }; } @@ -1023,39 +1028,37 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Char => FfiUnsafe { ty, - reason: "the `char` type has no C equivalent".into(), - help: Some("consider using `u32` or `libc::wchar_t` instead".into()), + reason: fluent::lint::improper_ctypes_char_reason, + help: Some(fluent::lint::improper_ctypes_char_help), }, - ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe { - ty, - reason: "128-bit integers don't currently have a known stable ABI".into(), - help: None, - }, + ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None } + } // Primitive types with a stable representation. ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, ty::Slice(_) => FfiUnsafe { ty, - reason: "slices have no C equivalent".into(), - help: Some("consider using a raw pointer instead".into()), + reason: fluent::lint::improper_ctypes_slice_reason, + help: Some(fluent::lint::improper_ctypes_slice_help), }, ty::Dynamic(..) => { - FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None } + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None } } ty::Str => FfiUnsafe { ty, - reason: "string slices have no C equivalent".into(), - help: Some("consider using `*const u8` and a length instead".into()), + reason: fluent::lint::improper_ctypes_str_reason, + help: Some(fluent::lint::improper_ctypes_str_help), }, ty::Tuple(..) => FfiUnsafe { ty, - reason: "tuples have unspecified layout".into(), - help: Some("consider using a struct instead".into()), + reason: fluent::lint::improper_ctypes_tuple_reason, + help: Some(fluent::lint::improper_ctypes_tuple_help), }, ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) @@ -1086,12 +1089,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if self.is_internal_abi(sig.abi()) { return FfiUnsafe { ty, - reason: "this function pointer has Rust-specific calling convention".into(), - help: Some( - "consider using an `extern fn(...) -> ...` \ - function pointer instead" - .into(), - ), + reason: fluent::lint::improper_ctypes_fnptr_reason, + help: Some(fluent::lint::improper_ctypes_fnptr_help), }; } @@ -1122,7 +1121,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // While opaque types are checked for earlier, if a projection in a struct field // normalizes to an opaque type, then it will reach this branch. ty::Opaque(..) => { - FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None } + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None } } // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe, @@ -1148,8 +1147,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { &mut self, ty: Ty<'tcx>, sp: Span, - note: &str, - help: Option<&str>, + note: DiagnosticMessage, + help: Option<DiagnosticMessage>, ) { let lint = match self.mode { CItemKind::Declaration => IMPROPER_CTYPES, @@ -1161,18 +1160,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Declaration => "block", CItemKind::Definition => "fn", }; - let mut diag = lint.build(&format!( - "`extern` {} uses type `{}`, which is not FFI-safe", - item_description, ty - )); - diag.span_label(sp, "not FFI-safe"); + let mut diag = lint.build(fluent::lint::improper_ctypes); + diag.set_arg("ty", ty); + diag.set_arg("desc", item_description); + diag.span_label(sp, fluent::lint::label); if let Some(help) = help { diag.help(help); } diag.note(note); if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { - diag.span_note(sp, "the type is defined here"); + diag.span_note(sp, fluent::lint::note); } } diag.emit(); @@ -1184,7 +1182,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } - impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { + impl<'a, 'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -1209,7 +1207,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { - self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); + self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None); true } else { false @@ -1251,13 +1249,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { - self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None); + self.emit_ffi_unsafe_type_lint( + ty, + sp, + fluent::lint::improper_ctypes_only_phantomdata, + None, + ); } // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic // argument, which after substitution, is `()`, then this branch can be hit. FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {} FfiResult::FfiUnsafe { ty, reason, help } => { - self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref()); + self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); } } } @@ -1384,12 +1387,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { VARIANT_SIZE_DIFFERENCES, enum_definition.variants[largest_index].span, |lint| { - lint.build(&format!( - "enum variant is more than three times \ - larger ({} bytes) than the next largest", - largest - )) - .emit(); + lint.build(fluent::lint::variant_size_differences) + .set_arg("largest", largest) + .emit(); }, ); } @@ -1483,49 +1483,42 @@ impl InvalidAtomicOrdering { None } - fn matches_ordering(cx: &LateContext<'_>, did: DefId, orderings: &[Symbol]) -> bool { + fn match_ordering(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<Symbol> { + let ExprKind::Path(ref ord_qpath) = ord_arg.kind else { return None }; + let did = cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()?; let tcx = cx.tcx; let atomic_ordering = tcx.get_diagnostic_item(sym::Ordering); - orderings.iter().any(|ordering| { - tcx.item_name(did) == *ordering && { - let parent = tcx.parent(did); - Some(parent) == atomic_ordering - // needed in case this is a ctor, not a variant - || tcx.opt_parent(parent) == atomic_ordering - } - }) - } - - fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> { - if let ExprKind::Path(ref ord_qpath) = ord_arg.kind { - cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id() - } else { - None - } + let name = tcx.item_name(did); + let parent = tcx.parent(did); + [sym::Relaxed, sym::Release, sym::Acquire, sym::AcqRel, sym::SeqCst].into_iter().find( + |&ordering| { + name == ordering + && (Some(parent) == atomic_ordering + // needed in case this is a ctor, not a variant + || tcx.opt_parent(parent) == atomic_ordering) + }, + ) } fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { - use rustc_hir::def::{DefKind, Res}; - use rustc_hir::QPath; if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) && let Some((ordering_arg, invalid_ordering)) = match method { sym::load => Some((&args[1], sym::Release)), sym::store => Some((&args[2], sym::Acquire)), _ => None, } - && let ExprKind::Path(QPath::Resolved(_, path)) = ordering_arg.kind - && let Res::Def(DefKind::Ctor(..), ctor_id) = path.res - && Self::matches_ordering(cx, ctor_id, &[invalid_ordering, sym::AcqRel]) + && let Some(ordering) = Self::match_ordering(cx, ordering_arg) + && (ordering == invalid_ordering || ordering == sym::AcqRel) { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| { if method == sym::load { - diag.build("atomic loads cannot have `Release` or `AcqRel` ordering") - .help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`") + diag.build(fluent::lint::atomic_ordering_load) + .help(fluent::lint::help) .emit() } else { debug_assert_eq!(method, sym::store); - diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering") - .help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`") + diag.build(fluent::lint::atomic_ordering_store) + .help(fluent::lint::help) .emit(); } }); @@ -1537,75 +1530,74 @@ impl InvalidAtomicOrdering { && let ExprKind::Path(ref func_qpath) = func.kind && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)) - && let ExprKind::Path(ref ordering_qpath) = &args[0].kind - && let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id() - && Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]) + && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| { - diag.build("memory fences cannot have `Relaxed` ordering") - .help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`") + diag.build(fluent::lint::atomic_ordering_fence) + .help(fluent::lint::help) .emit(); }); } } fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak]) - && let Some((success_order_arg, failure_order_arg)) = match method { - sym::fetch_update => Some((&args[1], &args[2])), - sym::compare_exchange | sym::compare_exchange_weak => Some((&args[3], &args[4])), - _ => None, - } - && let Some(fail_ordering_def_id) = Self::opt_ordering_defid(cx, failure_order_arg) - { - // Helper type holding on to some checking and error reporting data. Has - // - (success ordering, - // - list of failure orderings forbidden by the success order, - // - suggestion message) - type OrdLintInfo = (Symbol, &'static [Symbol], &'static str); - const RELAXED: OrdLintInfo = (sym::Relaxed, &[sym::SeqCst, sym::Acquire], "ordering mode `Relaxed`"); - const ACQUIRE: OrdLintInfo = (sym::Acquire, &[sym::SeqCst], "ordering modes `Acquire` or `Relaxed`"); - const SEQ_CST: OrdLintInfo = (sym::SeqCst, &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`"); - const RELEASE: OrdLintInfo = (sym::Release, RELAXED.1, RELAXED.2); - const ACQREL: OrdLintInfo = (sym::AcqRel, ACQUIRE.1, ACQUIRE.2); - const SEARCH: [OrdLintInfo; 5] = [RELAXED, ACQUIRE, SEQ_CST, RELEASE, ACQREL]; - - let success_lint_info = Self::opt_ordering_defid(cx, success_order_arg) - .and_then(|success_ord_def_id| -> Option<OrdLintInfo> { - SEARCH - .iter() - .copied() - .find(|(ordering, ..)| { - Self::matches_ordering(cx, success_ord_def_id, &[*ordering]) - }) - }); - if Self::matches_ordering(cx, fail_ordering_def_id, &[sym::Release, sym::AcqRel]) { - // If we don't know the success order is, use what we'd suggest - // if it were maximally permissive. - let suggested = success_lint_info.unwrap_or(SEQ_CST).2; - cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| { - let msg = format!( - "{}'s failure ordering may not be `Release` or `AcqRel`", - method, - ); - diag.build(&msg) - .help(&format!("consider using {} instead", suggested)) - .emit(); - }); - } else if let Some((success_ord, bad_ords_given_success, suggested)) = success_lint_info { - if Self::matches_ordering(cx, fail_ordering_def_id, bad_ords_given_success) { - cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| { - let msg = format!( - "{}'s failure ordering may not be stronger than the success ordering of `{}`", - method, - success_ord, - ); - diag.build(&msg) - .help(&format!("consider using {} instead", suggested)) - .emit(); - }); - } + let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak]) + else {return }; + + let (success_order_arg, fail_order_arg) = match method { + sym::fetch_update => (&args[1], &args[2]), + sym::compare_exchange | sym::compare_exchange_weak => (&args[3], &args[4]), + _ => return, + }; + + let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return }; + + if matches!(fail_ordering, sym::Release | sym::AcqRel) { + #[derive(LintDiagnostic)] + #[lint(lint::atomic_ordering_invalid)] + #[help] + struct InvalidAtomicOrderingDiag { + method: Symbol, + #[label] + fail_order_arg_span: Span, } + + cx.emit_spanned_lint( + INVALID_ATOMIC_ORDERING, + fail_order_arg.span, + InvalidAtomicOrderingDiag { method, fail_order_arg_span: fail_order_arg.span }, + ); + } + + let Some(success_ordering) = Self::match_ordering(cx, success_order_arg) else { return }; + + if matches!( + (success_ordering, fail_ordering), + (sym::Relaxed | sym::Release, sym::Acquire) + | (sym::Relaxed | sym::Release | sym::Acquire | sym::AcqRel, sym::SeqCst) + ) { + let success_suggestion = + if success_ordering == sym::Release && fail_ordering == sym::Acquire { + sym::AcqRel + } else { + fail_ordering + }; + cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| { + diag.build(fluent::lint::atomic_ordering_invalid_fail_success) + .set_arg("method", method) + .set_arg("fail_ordering", fail_ordering) + .set_arg("success_ordering", success_ordering) + .set_arg("success_suggestion", success_suggestion) + .span_label(fail_order_arg.span, fluent::lint::fail_label) + .span_label(success_order_arg.span, fluent::lint::success_label) + .span_suggestion_short( + success_order_arg.span, + fluent::lint::suggestion, + format!("std::sync::atomic::Ordering::{success_suggestion}"), + Applicability::MaybeIncorrect, + ) + .emit(); + }); } } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 73f353e62c177..53269d1852703 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_errors::{pluralize, Applicability, MultiSpan}; +use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -155,22 +155,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { if let Some(must_use_op) = must_use_op { cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| { - let mut lint = lint.build(&format!("unused {} that must be used", must_use_op)); - lint.span_label(expr.span, &format!("the {} produces a value", must_use_op)); - lint.span_suggestion_verbose( - expr.span.shrink_to_lo(), - "use `let _ = ...` to ignore the resulting value", - "let _ = ", - Applicability::MachineApplicable, - ); - lint.emit(); + lint.build(fluent::lint::unused_op) + .set_arg("op", must_use_op) + .span_label(expr.span, fluent::lint::label) + .span_suggestion_verbose( + expr.span.shrink_to_lo(), + fluent::lint::suggestion, + "let _ = ", + Applicability::MachineApplicable, + ) + .emit(); }); op_warned = true; } if !(type_permits_lack_of_use || fn_warned || op_warned) { cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| { - lint.build(&format!("unused result of type `{}`", ty)).emit(); + lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit(); }); } @@ -267,23 +268,27 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { }, ty::Closure(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let mut err = lint.build(&format!( - "unused {}closure{}{} that must be used", - descr_pre, plural_suffix, descr_post, - )); - err.note("closures are lazy and do nothing unless called"); - err.emit(); + // FIXME(davidtwco): this isn't properly translatable becauses of the + // pre/post strings + lint.build(fluent::lint::unused_closure) + .set_arg("count", plural_len) + .set_arg("pre", descr_pre) + .set_arg("post", descr_post) + .note(fluent::lint::note) + .emit(); }); true } ty::Generator(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let mut err = lint.build(&format!( - "unused {}generator{}{} that must be used", - descr_pre, plural_suffix, descr_post, - )); - err.note("generators are lazy and do nothing unless resumed"); - err.emit(); + // FIXME(davidtwco): this isn't properly translatable becauses of the + // pre/post strings + lint.build(fluent::lint::unused_generator) + .set_arg("count", plural_len) + .set_arg("pre", descr_pre) + .set_arg("post", descr_post) + .note(fluent::lint::note) + .emit(); }); true } @@ -305,13 +310,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ) -> bool { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let msg = format!( - "unused {}`{}`{} that must be used", - descr_pre_path, - cx.tcx.def_path_str(def_id), - descr_post_path - ); - let mut err = lint.build(&msg); + // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post + // strings + let mut err = lint.build(fluent::lint::unused_def); + err.set_arg("pre", descr_pre_path); + err.set_arg("post", descr_post_path); + err.set_arg("def", cx.tcx.def_path_str(def_id)); // check for #[must_use = "..."] if let Some(note) = attr.value_str() { err.note(note.as_str()); @@ -356,20 +360,20 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| { let ty = cx.typeck_results().expr_ty(expr); if ty.needs_drop(cx.tcx, cx.param_env) { - let mut lint = lint.build("path statement drops value"); + let mut lint = lint.build(fluent::lint::path_statement_drop); if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { lint.span_suggestion( s.span, - "use `drop` to clarify the intent", + fluent::lint::suggestion, format!("drop({});", snippet), Applicability::MachineApplicable, ); } else { - lint.span_help(s.span, "use `drop` to clarify the intent"); + lint.span_help(s.span, fluent::lint::suggestion); } lint.emit(); } else { - lint.build("path statement with no effect").emit(); + lint.build(fluent::lint::path_statement_no_effect).emit(); } }); } @@ -540,15 +544,19 @@ trait UnusedDelimLint { } cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| { - let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg); - let mut err = lint.build(&span_msg); let replacement = vec![ (spans.0, if keep_space.0 { " ".into() } else { "".into() }), (spans.1, if keep_space.1 { " ".into() } else { "".into() }), ]; - let suggestion = format!("remove these {}", Self::DELIM_STR); - err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable); - err.emit(); + lint.build(fluent::lint::unused_delim) + .set_arg("delim", Self::DELIM_STR) + .set_arg("item", msg) + .multipart_suggestion( + fluent::lint::suggestion, + replacement, + Applicability::MachineApplicable, + ) + .emit(); }); } @@ -1110,7 +1118,7 @@ impl UnusedImportBraces { }; cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| { - lint.build(&format!("braces around {} is unnecessary", node_name)).emit(); + lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit(); }); } } @@ -1161,15 +1169,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { for adj in cx.typeck_results().expr_adjustments(e) { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| { - let msg = match m { - adjustment::AutoBorrowMutability::Not => { - "unnecessary allocation, use `&` instead" - } + lint.build(match m { + adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation, adjustment::AutoBorrowMutability::Mut { .. } => { - "unnecessary allocation, use `&mut` instead" + fluent::lint::unused_allocation_mut } - }; - lint.build(msg).emit(); + }) + .emit(); }); } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b1bfd612b90e5..39690851d1ea8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -289,6 +289,7 @@ declare_lint! { "constant evaluation encountered erroneous expression", @future_incompatible = FutureIncompatibleInfo { reference: "issue #71800 <https://github.com/rust-lang/rust/issues/71800>", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; report_in_external_macro } @@ -519,6 +520,11 @@ declare_lint! { /// The `expect` attribute can be removed if this is intended behavior otherwise /// it should be investigated why the expected lint is no longer issued. /// + /// In rare cases, the expectation might be emitted at a different location than + /// shown in the shown code snippet. In most cases, the `#[expect]` attribute + /// works when added to the outer scope. A few lints can only be expected + /// on a crate level. + /// /// Part of RFC 2383. The progress is being tracked in [#54503] /// /// [#54503]: https://github.com/rust-lang/rust/issues/54503 @@ -3126,6 +3132,60 @@ declare_lint! { "detects unexpected names and values in `#[cfg]` conditions", } +declare_lint! { + /// The `repr_transparent_external_private_fields` lint + /// detects types marked `#[repr(transparent)]` that (transitively) + /// contain an external ZST type marked `#[non_exhaustive]` or containing + /// private fields + /// + /// ### Example + /// + /// ```rust,ignore (needs external crate) + /// #![deny(repr_transparent_external_private_fields)] + /// use foo::NonExhaustiveZst; + /// + /// #[repr(transparent)] + /// struct Bar(u32, ([u32; 0], NonExhaustiveZst)); + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + /// --> src/main.rs:5:28 + /// | + /// 5 | struct Bar(u32, ([u32; 0], NonExhaustiveZst)); + /// | ^^^^^^^^^^^^^^^^ + /// | + /// note: the lint level is defined here + /// --> src/main.rs:1:9 + /// | + /// 1 | #![deny(repr_transparent_external_private_fields)] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + /// = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + /// ``` + /// + /// ### Explanation + /// + /// Previous, Rust accepted fields that contain external private zero-sized types, + /// even though it should not be a breaking change to add a non-zero-sized field to + /// that private type. + /// + /// This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #78586] for more details. + /// + /// [issue #78586]: https://github.com/rust-lang/rust/issues/78586 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + Warn, + "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>", + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3230,6 +3290,9 @@ declare_lint_pass! { UNEXPECTED_CFGS, DEPRECATED_WHERE_CLAUSE_LOCATION, TEST_UNSTABLE_LINT, + FFI_UNWIND_CALLS, + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + NAMED_ARGUMENTS_USED_POSITIONALLY, ] } @@ -3895,3 +3958,72 @@ declare_lint! { "this unstable lint is only for testing", @feature_gate = sym::test_unstable_lint; } + +declare_lint! { + /// The `ffi_unwind_calls` lint detects calls to foreign functions or function pointers with + /// `C-unwind` or other FFI-unwind ABIs. + /// + /// ### Example + /// + /// ```rust,ignore (need FFI) + /// #![feature(ffi_unwind_calls)] + /// #![feature(c_unwind)] + /// + /// # mod impl { + /// # #[no_mangle] + /// # pub fn "C-unwind" fn foo() {} + /// # } + /// + /// extern "C-unwind" { + /// fn foo(); + /// } + /// + /// fn bar() { + /// unsafe { foo(); } + /// let ptr: unsafe extern "C-unwind" fn() = foo; + /// unsafe { ptr(); } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// For crates containing such calls, if they are compiled with `-C panic=unwind` then the + /// produced library cannot be linked with crates compiled with `-C panic=abort`. For crates + /// that desire this ability it is therefore necessary to avoid such calls. + pub FFI_UNWIND_CALLS, + Allow, + "call to foreign functions or function pointers with FFI-unwind ABI", + @feature_gate = sym::c_unwind; +} + +declare_lint! { + /// The `named_arguments_used_positionally` lint detects cases where named arguments are only + /// used positionally in format strings. This usage is valid but potentially very confusing. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(named_arguments_used_positionally)] + /// fn main() { + /// let _x = 5; + /// println!("{}", _x = 1); // Prints 1, will trigger lint + /// + /// println!("{}", _x); // Prints 5, no lint emitted + /// println!("{_x}", _x = _x); // Prints 5, no lint emitted + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust formatting strings can refer to named arguments by their position, but this usage is + /// potentially confusing. In particular, readers can incorrectly assume that the declaration + /// of named arguments is an assignment (which would produce the unit type). + /// For backwards compatibility, this is not a hard error. + pub NAMED_ARGUMENTS_USED_POSITIONALLY, + Warn, + "named arguments in format used positionally" +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1cd19c7eaab35..4fd57ed853379 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -232,6 +232,13 @@ impl Level { Level::Deny | Level::Forbid => true, } } + + pub fn get_expectation_id(&self) -> Option<LintExpectationId> { + match self { + Level::Expect(id) | Level::ForceWarn(Some(id)) => Some(*id), + _ => None, + } + } } /// Specification of a single lint. @@ -460,6 +467,7 @@ pub enum BuiltinLintDiagnostics { /// If true, the lifetime will be fully elided. use_span: Option<(Span, bool)>, }, + NamedArgumentUsedPositionally(Option<Span>, Span, String), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 38fddbdba54dd..be8fbf7677bcf 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -985,7 +985,9 @@ LLVMRustOptimizeWithNewPassManager( if (SanitizerOptions->SanitizeAddress) { OptimizerLastEPCallbacks.push_back( [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { +#if LLVM_VERSION_LT(15, 0) MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); +#endif #if LLVM_VERSION_GE(14, 0) AddressSanitizerOptions opts = AddressSanitizerOptions{ /*CompileKernel=*/false, @@ -1713,7 +1715,7 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data, // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void -LLVMRustLTOGetDICompileUnit(LLVMModuleRef Mod, +LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, DICompileUnit **A, DICompileUnit **B) { Module *M = unwrap(Mod); @@ -1731,7 +1733,7 @@ LLVMRustLTOGetDICompileUnit(LLVMModuleRef Mod, // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void -LLVMRustLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { +LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { Module *M = unwrap(Mod); // If the original source module didn't have a `DICompileUnit` then try to diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index a52d534024206..7ac3157e7a1de 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -411,8 +411,14 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, size_t ConstraintsLen) { +#if LLVM_VERSION_LT(15, 0) return InlineAsm::Verify(unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen)); +#else + // llvm::Error converts to true if it is an error. + return !llvm::errorToBool(InlineAsm::verify( + unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen))); +#endif } extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, @@ -1865,3 +1871,11 @@ extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) { GlobalValue *GV = unwrap<GlobalValue>(V); Mangler().getNameWithPrefix(OS, GV, true); } + +// LLVMGetAggregateElement was added in LLVM 15. For earlier LLVM versions just +// use its implementation. +#if LLVM_VERSION_LT(15, 0) +extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) { + return wrap(unwrap<Constant>(C)->getAggregateElement(Idx)); +} +#endif diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 95ee0d4a060d2..6b5b8b5932018 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -1,140 +1,77 @@ #![deny(unused_must_use)] -use crate::diagnostics::error::{ - invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, - SessionDiagnosticDeriveError, -}; -use crate::diagnostics::utils::{ - report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path, - Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, -}; -use proc_macro2::{Ident, TokenStream}; -use quote::{format_ident, quote}; -use std::collections::HashMap; -use std::str::FromStr; -use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type}; -use synstructure::{BindingInfo, Structure}; +use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind}; +use crate::diagnostics::error::{span_err, DiagnosticDeriveError}; +use crate::diagnostics::utils::{build_field_mapping, SetOnce}; +use proc_macro2::TokenStream; +use quote::quote; +use syn::spanned::Spanned; +use synstructure::Structure; /// The central struct for constructing the `into_diagnostic` method from an annotated struct. pub(crate) struct SessionDiagnosticDerive<'a> { structure: Structure<'a>, - builder: SessionDiagnosticDeriveBuilder, + sess: syn::Ident, + builder: DiagnosticDeriveBuilder, } impl<'a> SessionDiagnosticDerive<'a> { pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self { - // Build the mapping of field names to fields. This allows attributes to peek values from - // other fields. - let mut fields_map = HashMap::new(); - - // Convenience bindings. - let ast = structure.ast(); - - if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data { - for field in fields.iter() { - if let Some(ident) = &field.ident { - fields_map.insert(ident.to_string(), quote! { &self.#ident }); - } - } - } - Self { - builder: SessionDiagnosticDeriveBuilder { + builder: DiagnosticDeriveBuilder { diag, - sess, - fields: fields_map, + fields: build_field_mapping(&structure), kind: None, code: None, slug: None, }, + sess, structure, } } pub(crate) fn into_tokens(self) -> TokenStream { - let SessionDiagnosticDerive { mut structure, mut builder } = self; + let SessionDiagnosticDerive { mut structure, sess, mut builder } = self; let ast = structure.ast(); - let attrs = &ast.attrs; - let (implementation, param_ty) = { if let syn::Data::Struct(..) = ast.data { - let preamble = { - let preamble = attrs.iter().map(|attr| { - builder - .generate_structure_code(attr) - .unwrap_or_else(|v| v.to_compile_error()) - }); - - quote! { - #(#preamble)*; - } - }; - - // Keep track of which fields are subdiagnostics or have no attributes. - let mut subdiagnostics_or_empty = std::collections::HashSet::new(); - - // Generates calls to `span_label` and similar functions based on the attributes - // on fields. Code for suggestions uses formatting machinery and the value of - // other fields - because any given field can be referenced multiple times, it - // should be accessed through a borrow. When passing fields to `add_subdiagnostic` - // or `set_arg` (which happens below) for Fluent, we want to move the data, so that - // has to happen in a separate pass over the fields. - let attrs = structure - .clone() - .filter(|field_binding| { - let attrs = &field_binding.ast().attrs; - - (!attrs.is_empty() - && attrs.iter().all(|attr| { - "subdiagnostic" - != attr.path.segments.last().unwrap().ident.to_string() - })) - || { - subdiagnostics_or_empty.insert(field_binding.binding.clone()); - false - } - }) - .each(|field_binding| builder.generate_field_attrs_code(field_binding)); - - structure.bind_with(|_| synstructure::BindStyle::Move); - // When a field has attributes like `#[label]` or `#[note]` then it doesn't - // need to be passed as an argument to the diagnostic. But when a field has no - // attributes or a `#[subdiagnostic]` attribute then it must be passed as an - // argument to the diagnostic so that it can be referred to by Fluent messages. - let args = structure - .filter(|field_binding| { - subdiagnostics_or_empty.contains(&field_binding.binding) - }) - .each(|field_binding| builder.generate_field_attrs_code(field_binding)); + let preamble = builder.preamble(&structure); + let (attrs, args) = builder.body(&mut structure); let span = ast.span().unwrap(); - let (diag, sess) = (&builder.diag, &builder.sess); - let init = match (builder.kind, builder.slug) { + let diag = &builder.diag; + let init = match (builder.kind.value(), builder.slug.value()) { (None, _) => { span_err(span, "diagnostic kind not specified") .help("use the `#[error(...)]` attribute to create an error") .emit(); - return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - (Some((kind, _)), None) => { - span_err(span, "`slug` not specified") - .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr())) + (Some(kind), None) => { + span_err(span, "diagnostic slug not specified") + .help(&format!( + "specify the slug as the first argument to the attribute, such as \ + `#[{}(typeck::example_error)]`", + kind.descr() + )) .emit(); - return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => { + (Some(DiagnosticDeriveKind::Lint), _) => { + span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported") + .help("use the `#[error(...)]` attribute to create a error") + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + } + (Some(DiagnosticDeriveKind::Error), Some(slug)) => { quote! { - let mut #diag = #sess.struct_err( - rustc_errors::DiagnosticMessage::new(#slug), - ); + let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug); } } - (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => { + (Some(DiagnosticDeriveKind::Warn), Some(slug)) => { quote! { - let mut #diag = #sess.struct_warn( - rustc_errors::DiagnosticMessage::new(#slug), - ); + let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug); } } }; @@ -151,10 +88,12 @@ impl<'a> SessionDiagnosticDerive<'a> { #diag }; let param_ty = match builder.kind { - Some((SessionDiagnosticKind::Error, _)) => { + Some((DiagnosticDeriveKind::Error, _)) => { quote! { rustc_errors::ErrorGuaranteed } } - Some((SessionDiagnosticKind::Warn, _)) => quote! { () }, + Some((DiagnosticDeriveKind::Lint | DiagnosticDeriveKind::Warn, _)) => { + quote! { () } + } _ => unreachable!(), }; @@ -166,13 +105,12 @@ impl<'a> SessionDiagnosticDerive<'a> { ) .emit(); - let implementation = SessionDiagnosticDeriveError::ErrorHandled.to_compile_error(); + let implementation = DiagnosticDeriveError::ErrorHandled.to_compile_error(); let param_ty = quote! { rustc_errors::ErrorGuaranteed }; (implementation, param_ty) } }; - let sess = &builder.sess; structure.gen_impl(quote! { gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty> for @Self @@ -189,419 +127,99 @@ impl<'a> SessionDiagnosticDerive<'a> { } } -/// What kind of session diagnostic is being derived - an error or a warning? -#[derive(Copy, Clone)] -enum SessionDiagnosticKind { - /// `#[error(..)]` - Error, - /// `#[warn(..)]` - Warn, +/// The central struct for constructing the `decorate_lint` method from an annotated struct. +pub(crate) struct LintDiagnosticDerive<'a> { + structure: Structure<'a>, + builder: DiagnosticDeriveBuilder, } -impl SessionDiagnosticKind { - /// Returns human-readable string corresponding to the kind. - fn descr(&self) -> &'static str { - match self { - SessionDiagnosticKind::Error => "error", - SessionDiagnosticKind::Warn => "warning", +impl<'a> LintDiagnosticDerive<'a> { + pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self { + Self { + builder: DiagnosticDeriveBuilder { + diag, + fields: build_field_mapping(&structure), + kind: None, + code: None, + slug: None, + }, + structure, } } -} - -/// Tracks persistent information required for building up the individual calls to diagnostic -/// methods for the final generated method. This is a separate struct to `SessionDiagnosticDerive` -/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a -/// double mut borrow later on. -struct SessionDiagnosticDeriveBuilder { - /// Name of the session parameter that's passed in to the `as_error` method. - sess: syn::Ident, - /// The identifier to use for the generated `DiagnosticBuilder` instance. - diag: syn::Ident, - - /// Store a map of field name to its corresponding field. This is built on construction of the - /// derive builder. - fields: HashMap<String, TokenStream>, - - /// Kind of diagnostic requested via the struct attribute. - kind: Option<(SessionDiagnosticKind, proc_macro::Span)>, - /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that - /// has the actual diagnostic message. - slug: Option<(String, proc_macro::Span)>, - /// Error codes are a optional part of the struct attribute - this is only set to detect - /// multiple specifications. - code: Option<(String, proc_macro::Span)>, -} -impl HasFieldMap for SessionDiagnosticDeriveBuilder { - fn get_field_binding(&self, field: &String) -> Option<&TokenStream> { - self.fields.get(field) - } -} - -impl SessionDiagnosticDeriveBuilder { - /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct - /// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates - /// diagnostic builder calls for setting error code and creating note/help messages. - fn generate_structure_code( - &mut self, - attr: &Attribute, - ) -> Result<TokenStream, SessionDiagnosticDeriveError> { - let span = attr.span().unwrap(); - - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - let meta = attr.parse_meta()?; - - if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) { - let diag = &self.diag; - let id = match meta { - Meta::Path(..) => quote! { #name }, - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - quote! { #s } - } - _ => unreachable!(), - }; - let fn_name = proc_macro2::Ident::new(name, attr.span()); - - return Ok(quote! { - #diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id)); - }); - } - - let nested = match meta { - Meta::List(MetaList { ref nested, .. }) => nested, - _ => throw_invalid_attr!(attr, &meta), - }; - - let kind = match name { - "error" => SessionDiagnosticKind::Error, - "warning" => SessionDiagnosticKind::Warn, - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `error` and `warning` are valid attributes") - }), - }; - self.kind.set_once((kind, span)); + pub(crate) fn into_tokens(self) -> TokenStream { + let LintDiagnosticDerive { mut structure, mut builder } = self; - let mut tokens = Vec::new(); - for nested_attr in nested { - let meta = match nested_attr { - syn::NestedMeta::Meta(meta) => meta, - _ => throw_invalid_nested_attr!(attr, &nested_attr), - }; + let ast = structure.ast(); + let implementation = { + if let syn::Data::Struct(..) = ast.data { + let preamble = builder.preamble(&structure); + let (attrs, args) = builder.body(&mut structure); - let path = meta.path(); - let nested_name = path.segments.last().unwrap().ident.to_string(); - match &meta { - // Struct attributes are only allowed to be applied once, and the diagnostic - // changes will be set in the initialisation code. - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - let span = s.span().unwrap(); - match nested_name.as_str() { - "slug" => { - self.slug.set_once((s.value(), span)); - } - "code" => { - self.code.set_once((s.value(), span)); - let (diag, code) = (&self.diag, &self.code.as_ref().map(|(v, _)| v)); - tokens.push(quote! { - #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); - }); - } - _ => invalid_nested_attr(attr, &nested_attr) - .help("only `slug` and `code` are valid nested attributes") - .emit(), + let diag = &builder.diag; + let span = ast.span().unwrap(); + let init = match (builder.kind.value(), builder.slug.value()) { + (None, _) => { + span_err(span, "diagnostic kind not specified") + .help("use the `#[error(...)]` attribute to create an error") + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - } - _ => invalid_nested_attr(attr, &nested_attr).emit(), - } - } - - Ok(tokens.drain(..).collect()) - } - - fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { - let field = binding_info.ast(); - let field_binding = &binding_info.binding; - - let inner_ty = FieldInnerTy::from_type(&field.ty); - - // When generating `set_arg` or `add_subdiagnostic` calls, move data rather than - // borrow it to avoid requiring clones - this must therefore be the last use of - // each field (for example, any formatting machinery that might refer to a field - // should be generated already). - if field.attrs.is_empty() { - let diag = &self.diag; - let ident = field.ident.as_ref().unwrap(); - quote! { - #diag.set_arg( - stringify!(#ident), - #field_binding - ); - } - } else { - field - .attrs - .iter() - .map(move |attr| { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let (binding, needs_destructure) = match (name.as_str(), &inner_ty) { - // `primary_span` can accept a `Vec<Span>` so don't destructure that. - ("primary_span", FieldInnerTy::Vec(_)) => { - (quote! { #field_binding.clone() }, false) - } - // `subdiagnostics` are not derefed because they are bound by value. - ("subdiagnostic", _) => (quote! { #field_binding }, true), - _ => (quote! { *#field_binding }, true), - }; - - let generated_code = self - .generate_inner_field_code( - attr, - FieldInfo { - binding: binding_info, - ty: inner_ty.inner_type().unwrap_or(&field.ty), - span: &field.span(), - }, - binding, - ) - .unwrap_or_else(|v| v.to_compile_error()); - - if needs_destructure { - inner_ty.with(field_binding, generated_code) - } else { - generated_code + (Some(kind), None) => { + span_err(span, "diagnostic slug not specified") + .help(&format!( + "specify the slug as the first argument to the attribute, such as \ + `#[{}(typeck::example_error)]`", + kind.descr() + )) + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - }) - .collect() - } - } - - fn generate_inner_field_code( - &mut self, - attr: &Attribute, - info: FieldInfo<'_>, - binding: TokenStream, - ) -> Result<TokenStream, SessionDiagnosticDeriveError> { - let diag = &self.diag; - - let ident = &attr.path.segments.last().unwrap().ident; - let name = ident.to_string(); - let name = name.as_str(); - - let meta = attr.parse_meta()?; - match meta { - Meta::Path(_) => match name { - "skip_arg" => { - // Don't need to do anything - by virtue of the attribute existing, the - // `set_arg` call will not be generated. - Ok(quote! {}) - } - "primary_span" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(quote! { - #diag.set_span(#binding); - }) - } - "label" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, ident, name)) - } - "note" | "help" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - Ok(self.add_spanned_subdiagnostic(binding, ident, name)) - } else if type_is_unit(&info.ty) { - Ok(self.add_subdiagnostic(ident, name)) - } else { - report_type_error(attr, "`Span` or `()`")?; + (Some(DiagnosticDeriveKind::Error | DiagnosticDeriveKind::Warn), _) => { + span_err(span, "only `#[lint(..)]` is supported") + .help("use the `#[lint(...)]` attribute to create a lint") + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - } - "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }), - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag - .help("only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes") - }), - }, - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name { - "label" => { - report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value())) - } - "note" | "help" => { - if type_matches_path(&info.ty, &["rustc_span", "Span"]) { - Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value())) - } else if type_is_unit(&info.ty) { - Ok(self.add_subdiagnostic(ident, &s.value())) - } else { - report_type_error(attr, "`Span` or `()`")?; + (Some(DiagnosticDeriveKind::Lint), Some(slug)) => { + quote! { + let mut #diag = #diag.build(rustc_errors::fluent::#slug); + } } - } - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `label`, `note` and `help` are valid field attributes") - }), - }, - Meta::List(MetaList { ref path, ref nested, .. }) => { - let name = path.segments.last().unwrap().ident.to_string(); - let name = name.as_ref(); - - match name { - "suggestion" | "suggestion_short" | "suggestion_hidden" - | "suggestion_verbose" => (), - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag - .help("only `suggestion{,_short,_hidden,_verbose}` are valid field attributes") - }), }; - let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?; - - let mut msg = None; - let mut code = None; - - for nested_attr in nested { - let meta = match nested_attr { - syn::NestedMeta::Meta(ref meta) => meta, - syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr), - }; - - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - let span = meta.span().unwrap(); - match nested_name { - "message" => { - msg = Some(s.value()); - } - "code" => { - let formatted_str = self.build_format(&s.value(), s.span()); - code = Some(formatted_str); - } - "applicability" => { - applicability = match applicability { - Some(v) => { - span_err( - span, - "applicability cannot be set in both the field and attribute" - ).emit(); - Some(v) - } - None => match Applicability::from_str(&s.value()) { - Ok(v) => Some(quote! { #v }), - Err(()) => { - span_err(span, "invalid applicability").emit(); - None - } - }, - } - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "only `message`, `code` and `applicability` are valid field attributes", - ) - }), - } - } - _ => throw_invalid_nested_attr!(attr, &nested_attr), + let implementation = quote! { + #init + #preamble + match self { + #attrs } - } - - let applicability = applicability - .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); - - let method = format_ident!("span_{}", name); - - let msg = msg.as_deref().unwrap_or("suggestion"); - let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) }; - let code = code.unwrap_or_else(|| quote! { String::new() }); - - Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); }) - } - _ => throw_invalid_attr!(attr, &meta), - } - } - - /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug - /// and `fluent_attr_identifier`. - fn add_spanned_subdiagnostic( - &self, - field_binding: TokenStream, - kind: &Ident, - fluent_attr_identifier: &str, - ) -> TokenStream { - let diag = &self.diag; - let fn_name = format_ident!("span_{}", kind); - quote! { - #diag.#fn_name( - #field_binding, - rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier) - ); - } - } + match self { + #args + } + #diag.emit(); + }; - /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug - /// and `fluent_attr_identifier`. - fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream { - let diag = &self.diag; - quote! { - #diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)); - } - } + implementation + } else { + span_err( + ast.span().unwrap(), + "`#[derive(LintDiagnostic)]` can only be used on structs", + ) + .emit(); - fn span_and_applicability_of_ty( - &self, - info: FieldInfo<'_>, - ) -> Result<(TokenStream, Option<TokenStream>), SessionDiagnosticDeriveError> { - match &info.ty { - // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`. - ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => { - let binding = &info.binding.binding; - Ok((quote!(*#binding), None)) + DiagnosticDeriveError::ErrorHandled.to_compile_error() } - // If `ty` is `(Span, Applicability)` then return tokens accessing those. - Type::Tuple(tup) => { - let mut span_idx = None; - let mut applicability_idx = None; - - for (idx, elem) in tup.elems.iter().enumerate() { - if type_matches_path(elem, &["rustc_span", "Span"]) { - if span_idx.is_none() { - span_idx = Some(syn::Index::from(idx)); - } else { - throw_span_err!( - info.span.unwrap(), - "type of field annotated with `#[suggestion(...)]` contains more than one `Span`" - ); - } - } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) { - if applicability_idx.is_none() { - applicability_idx = Some(syn::Index::from(idx)); - } else { - throw_span_err!( - info.span.unwrap(), - "type of field annotated with `#[suggestion(...)]` contains more than one Applicability" - ); - } - } - } - - if let Some(span_idx) = span_idx { - let binding = &info.binding.binding; - let span = quote!(#binding.#span_idx); - let applicability = applicability_idx - .map(|applicability_idx| quote!(#binding.#applicability_idx)) - .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); + }; - return Ok((span, Some(applicability))); + let diag = &builder.diag; + structure.gen_impl(quote! { + gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self { + fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) { + use rustc_errors::IntoDiagnosticArg; + #implementation } - - throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| { - diag.help("`#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`") - }); } - // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error. - _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| { - diag.help("`#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`") - }), - } + }) } } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs new file mode 100644 index 0000000000000..5c5275b7cfb92 --- /dev/null +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -0,0 +1,630 @@ +#![deny(unused_must_use)] + +use crate::diagnostics::error::{ + invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, + DiagnosticDeriveError, +}; +use crate::diagnostics::utils::{ + report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path, + Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce, +}; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{format_ident, quote}; +use std::collections::HashMap; +use std::str::FromStr; +use syn::{ + parse_quote, spanned::Spanned, Attribute, Field, Meta, MetaList, MetaNameValue, NestedMeta, + Path, Type, +}; +use synstructure::{BindingInfo, Structure}; + +/// What kind of diagnostic is being derived - an error, a warning or a lint? +#[derive(Copy, Clone)] +pub(crate) enum DiagnosticDeriveKind { + /// `#[error(..)]` + Error, + /// `#[warn(..)]` + Warn, + /// `#[lint(..)]` + Lint, +} + +impl DiagnosticDeriveKind { + /// Returns human-readable string corresponding to the kind. + pub fn descr(&self) -> &'static str { + match self { + DiagnosticDeriveKind::Error => "error", + DiagnosticDeriveKind::Warn => "warning", + DiagnosticDeriveKind::Lint => "lint", + } + } +} + +/// Tracks persistent information required for building up individual calls to diagnostic methods +/// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and +/// `LintDiagnostic` for lints. +pub(crate) struct DiagnosticDeriveBuilder { + /// The identifier to use for the generated `DiagnosticBuilder` instance. + pub diag: syn::Ident, + + /// Store a map of field name to its corresponding field. This is built on construction of the + /// derive builder. + pub fields: HashMap<String, TokenStream>, + + /// Kind of diagnostic requested via the struct attribute. + pub kind: Option<(DiagnosticDeriveKind, proc_macro::Span)>, + /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that + /// has the actual diagnostic message. + pub slug: Option<(Path, proc_macro::Span)>, + /// Error codes are a optional part of the struct attribute - this is only set to detect + /// multiple specifications. + pub code: Option<(String, proc_macro::Span)>, +} + +impl HasFieldMap for DiagnosticDeriveBuilder { + fn get_field_binding(&self, field: &String) -> Option<&TokenStream> { + self.fields.get(field) + } +} + +impl DiagnosticDeriveBuilder { + pub fn preamble<'s>(&mut self, structure: &Structure<'s>) -> TokenStream { + let ast = structure.ast(); + let attrs = &ast.attrs; + let preamble = attrs.iter().map(|attr| { + self.generate_structure_code_for_attr(attr).unwrap_or_else(|v| v.to_compile_error()) + }); + + quote! { + #(#preamble)*; + } + } + + pub fn body<'s>(&mut self, structure: &mut Structure<'s>) -> (TokenStream, TokenStream) { + // Keep track of which fields need to be handled with a by-move binding. + let mut needs_moved = std::collections::HashSet::new(); + + // Generates calls to `span_label` and similar functions based on the attributes + // on fields. Code for suggestions uses formatting machinery and the value of + // other fields - because any given field can be referenced multiple times, it + // should be accessed through a borrow. When passing fields to `add_subdiagnostic` + // or `set_arg` (which happens below) for Fluent, we want to move the data, so that + // has to happen in a separate pass over the fields. + let attrs = structure + .clone() + .filter(|field_binding| { + let ast = &field_binding.ast(); + !self.needs_move(ast) || { + needs_moved.insert(field_binding.binding.clone()); + false + } + }) + .each(|field_binding| self.generate_field_attrs_code(field_binding)); + + structure.bind_with(|_| synstructure::BindStyle::Move); + // When a field has attributes like `#[label]` or `#[note]` then it doesn't + // need to be passed as an argument to the diagnostic. But when a field has no + // attributes or a `#[subdiagnostic]` attribute then it must be passed as an + // argument to the diagnostic so that it can be referred to by Fluent messages. + let args = structure + .filter(|field_binding| needs_moved.contains(&field_binding.binding)) + .each(|field_binding| self.generate_field_attrs_code(field_binding)); + + (attrs, args) + } + + /// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic + /// call (like `span_label`). + fn should_generate_set_arg(&self, field: &Field) -> bool { + field.attrs.is_empty() + } + + /// Returns `true` if `field` needs to have code generated in the by-move branch of the + /// generated derive rather than the by-ref branch. + fn needs_move(&self, field: &Field) -> bool { + let generates_set_arg = self.should_generate_set_arg(field); + let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]); + // FIXME(davidtwco): better support for one field needing to be in the by-move and + // by-ref branches. + let is_subdiagnostic = field + .attrs + .iter() + .map(|attr| attr.path.segments.last().unwrap().ident.to_string()) + .any(|attr| attr == "subdiagnostic"); + + // `set_arg` calls take their argument by-move.. + generates_set_arg + // If this is a `MultiSpan` field then it needs to be moved to be used by any + // attribute.. + || is_multispan + // If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is + // unlikely to be `Copy`.. + || is_subdiagnostic + } + + /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct + /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates + /// diagnostic builder calls for setting error code and creating note/help messages. + fn generate_structure_code_for_attr( + &mut self, + attr: &Attribute, + ) -> Result<TokenStream, DiagnosticDeriveError> { + let diag = &self.diag; + let span = attr.span().unwrap(); + + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + let meta = attr.parse_meta()?; + + let is_help_note_or_warn = matches!(name, "help" | "note" | "warn_"); + + let nested = match meta { + // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or + // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug. + Meta::List(MetaList { ref nested, .. }) => nested, + // Subdiagnostics without spans can be applied to the type too, and these are just + // paths: `#[help]` and `#[note]` + Meta::Path(_) if is_help_note_or_warn => { + let fn_name = if name == "warn_" { + Ident::new("warn", attr.span()) + } else { + Ident::new(name, attr.span()) + }; + return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); }); + } + _ => throw_invalid_attr!(attr, &meta), + }; + + // Check the kind before doing any further processing so that there aren't misleading + // "no kind specified" errors if there are failures later. + match name { + "error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)), + "warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)), + "lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)), + "help" | "note" | "warn_" => (), + _ => throw_invalid_attr!(attr, &meta, |diag| { + diag.help( + "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes", + ) + }), + } + + // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or + // `#[help(typeck::another_help)]`. + let mut nested_iter = nested.into_iter(); + if let Some(nested_attr) = nested_iter.next() { + // Report an error if there are any other list items after the path. + if is_help_note_or_warn && nested_iter.next().is_some() { + throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "`help`, `note` and `warn_` struct attributes can only have one argument", + ) + }); + } + + match nested_attr { + NestedMeta::Meta(Meta::Path(path)) if is_help_note_or_warn => { + let fn_name = proc_macro2::Ident::new(name, attr.span()); + return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); }); + } + NestedMeta::Meta(Meta::Path(path)) => { + self.slug.set_once((path.clone(), span)); + } + NestedMeta::Meta(meta @ Meta::NameValue(_)) + if !is_help_note_or_warn + && meta.path().segments.last().unwrap().ident.to_string() == "code" => + { + // don't error for valid follow-up attributes + } + nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("first argument of the attribute should be the diagnostic slug") + }), + }; + } + + // Remaining attributes are optional, only `code = ".."` at the moment. + let mut tokens = Vec::new(); + for nested_attr in nested_iter { + let meta = match nested_attr { + syn::NestedMeta::Meta(meta) => meta, + _ => throw_invalid_nested_attr!(attr, &nested_attr), + }; + + let path = meta.path(); + let nested_name = path.segments.last().unwrap().ident.to_string(); + // Struct attributes are only allowed to be applied once, and the diagnostic + // changes will be set in the initialisation code. + if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta { + let span = s.span().unwrap(); + match nested_name.as_str() { + "code" => { + self.code.set_once((s.value(), span)); + let code = &self.code.as_ref().map(|(v, _)| v); + tokens.push(quote! { + #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string())); + }); + } + _ => invalid_nested_attr(attr, &nested_attr) + .help("only `code` is a valid nested attributes following the slug") + .emit(), + } + } else { + invalid_nested_attr(attr, &nested_attr).emit() + } + } + + Ok(tokens.drain(..).collect()) + } + + fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { + let field = binding_info.ast(); + let field_binding = &binding_info.binding; + + if self.should_generate_set_arg(&field) { + let diag = &self.diag; + let ident = field.ident.as_ref().unwrap(); + return quote! { + #diag.set_arg( + stringify!(#ident), + #field_binding + ); + }; + } + + let needs_move = self.needs_move(&field); + let inner_ty = FieldInnerTy::from_type(&field.ty); + + field + .attrs + .iter() + .map(move |attr| { + let name = attr.path.segments.last().unwrap().ident.to_string(); + let needs_clone = + name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); + let (binding, needs_destructure) = if needs_clone { + // `primary_span` can accept a `Vec<Span>` so don't destructure that. + (quote! { #field_binding.clone() }, false) + } else if needs_move { + (quote! { #field_binding }, true) + } else { + (quote! { *#field_binding }, true) + }; + + let generated_code = self + .generate_inner_field_code( + attr, + FieldInfo { + binding: binding_info, + ty: inner_ty.inner_type().unwrap_or(&field.ty), + span: &field.span(), + }, + binding, + ) + .unwrap_or_else(|v| v.to_compile_error()); + + if needs_destructure { + inner_ty.with(field_binding, generated_code) + } else { + generated_code + } + }) + .collect() + } + + fn generate_inner_field_code( + &mut self, + attr: &Attribute, + info: FieldInfo<'_>, + binding: TokenStream, + ) -> Result<TokenStream, DiagnosticDeriveError> { + let meta = attr.parse_meta()?; + match meta { + Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding), + Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding), + _ => throw_invalid_attr!(attr, &meta), + } + } + + fn generate_inner_field_code_path( + &mut self, + attr: &Attribute, + info: FieldInfo<'_>, + binding: TokenStream, + ) -> Result<TokenStream, DiagnosticDeriveError> { + assert!(matches!(attr.parse_meta()?, Meta::Path(_))); + let diag = &self.diag; + + let meta = attr.parse_meta()?; + + let ident = &attr.path.segments.last().unwrap().ident; + let name = ident.to_string(); + let name = name.as_str(); + match name { + "skip_arg" => { + // Don't need to do anything - by virtue of the attribute existing, the + // `set_arg` call will not be generated. + Ok(quote! {}) + } + "primary_span" => { + report_error_if_not_applied_to_span(attr, &info)?; + Ok(quote! { + #diag.set_span(#binding); + }) + } + "label" => { + report_error_if_not_applied_to_span(attr, &info)?; + Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label })) + } + "note" | "help" | "warn_" => { + let warn_ident = Ident::new("warn", Span::call_site()); + let (ident, path) = match name { + "note" => (ident, parse_quote! { _subdiag::note }), + "help" => (ident, parse_quote! { _subdiag::help }), + "warn_" => (&warn_ident, parse_quote! { _subdiag::warn }), + _ => unreachable!(), + }; + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + Ok(self.add_spanned_subdiagnostic(binding, ident, path)) + } else if type_is_unit(&info.ty) { + Ok(self.add_subdiagnostic(ident, path)) + } else { + report_type_error(attr, "`Span` or `()`")? + } + } + "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }), + _ => throw_invalid_attr!(attr, &meta, |diag| { + diag.help( + "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \ + are valid field attributes", + ) + }), + } + } + + fn generate_inner_field_code_list( + &mut self, + attr: &Attribute, + info: FieldInfo<'_>, + binding: TokenStream, + ) -> Result<TokenStream, DiagnosticDeriveError> { + let meta = attr.parse_meta()?; + let Meta::List(MetaList { ref path, ref nested, .. }) = meta else { unreachable!() }; + + let ident = &attr.path.segments.last().unwrap().ident; + let name = path.segments.last().unwrap().ident.to_string(); + let name = name.as_ref(); + match name { + "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => { + return self.generate_inner_field_code_suggestion(attr, info); + } + "label" | "help" | "note" | "warn_" => (), + _ => throw_invalid_attr!(attr, &meta, |diag| { + diag.help( + "only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \ + valid field attributes", + ) + }), + } + + // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a + // path, e.g. `#[label(typeck::label)]`. + let mut nested_iter = nested.into_iter(); + let msg = match nested_iter.next() { + Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(), + Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr), + None => throw_invalid_attr!(attr, &meta), + }; + + // None of these attributes should have anything following the slug. + if nested_iter.next().is_some() { + throw_invalid_attr!(attr, &meta); + } + + match name { + "label" => { + report_error_if_not_applied_to_span(attr, &info)?; + Ok(self.add_spanned_subdiagnostic(binding, ident, msg)) + } + "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => { + Ok(self.add_spanned_subdiagnostic(binding, ident, msg)) + } + "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)), + // `warn_` must be special-cased because the attribute `warn` already has meaning and + // so isn't used, despite the diagnostic API being named `warn`. + "warn_" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self + .add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)), + "warn_" if type_is_unit(&info.ty) => { + Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg)) + } + "note" | "help" | "warn_" => report_type_error(attr, "`Span` or `()`")?, + _ => unreachable!(), + } + } + + fn generate_inner_field_code_suggestion( + &mut self, + attr: &Attribute, + info: FieldInfo<'_>, + ) -> Result<TokenStream, DiagnosticDeriveError> { + let diag = &self.diag; + + let mut meta = attr.parse_meta()?; + let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta else { unreachable!() }; + + let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?; + + let mut msg = None; + let mut code = None; + + let mut nested_iter = nested.into_iter().peekable(); + if let Some(nested_attr) = nested_iter.peek() { + if let NestedMeta::Meta(Meta::Path(path)) = nested_attr { + msg = Some(path.clone()); + } + }; + // Move the iterator forward if a path was found (don't otherwise so that + // code/applicability can be found or an error emitted). + if msg.is_some() { + let _ = nested_iter.next(); + } + + for nested_attr in nested_iter { + let meta = match nested_attr { + syn::NestedMeta::Meta(ref meta) => meta, + syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr), + }; + + let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + let nested_name = nested_name.as_str(); + match meta { + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + let span = meta.span().unwrap(); + match nested_name { + "code" => { + let formatted_str = self.build_format(&s.value(), s.span()); + code = Some(formatted_str); + } + "applicability" => { + applicability = match applicability { + Some(v) => { + span_err( + span, + "applicability cannot be set in both the field and \ + attribute", + ) + .emit(); + Some(v) + } + None => match Applicability::from_str(&s.value()) { + Ok(v) => Some(quote! { #v }), + Err(()) => { + span_err(span, "invalid applicability").emit(); + None + } + }, + } + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "only `message`, `code` and `applicability` are valid field \ + attributes", + ) + }), + } + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + if matches!(meta, Meta::Path(_)) { + diag.help("a diagnostic slug must be the first argument to the attribute") + } else { + diag + } + }), + } + } + + let applicability = + applicability.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); + + let name = path.segments.last().unwrap().ident.to_string(); + let method = format_ident!("span_{}", name); + + let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion }); + let msg = quote! { rustc_errors::fluent::#msg }; + let code = code.unwrap_or_else(|| quote! { String::new() }); + + Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); }) + } + + /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug + /// and `fluent_attr_identifier`. + fn add_spanned_subdiagnostic( + &self, + field_binding: TokenStream, + kind: &Ident, + fluent_attr_identifier: Path, + ) -> TokenStream { + let diag = &self.diag; + let fn_name = format_ident!("span_{}", kind); + quote! { + #diag.#fn_name( + #field_binding, + rustc_errors::fluent::#fluent_attr_identifier + ); + } + } + + /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug + /// and `fluent_attr_identifier`. + fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream { + let diag = &self.diag; + quote! { + #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier); + } + } + + fn span_and_applicability_of_ty( + &self, + info: FieldInfo<'_>, + ) -> Result<(TokenStream, Option<TokenStream>), DiagnosticDeriveError> { + match &info.ty { + // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`. + ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => { + let binding = &info.binding.binding; + Ok((quote!(*#binding), None)) + } + // If `ty` is `(Span, Applicability)` then return tokens accessing those. + Type::Tuple(tup) => { + let mut span_idx = None; + let mut applicability_idx = None; + + for (idx, elem) in tup.elems.iter().enumerate() { + if type_matches_path(elem, &["rustc_span", "Span"]) { + if span_idx.is_none() { + span_idx = Some(syn::Index::from(idx)); + } else { + throw_span_err!( + info.span.unwrap(), + "type of field annotated with `#[suggestion(...)]` contains more \ + than one `Span`" + ); + } + } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) { + if applicability_idx.is_none() { + applicability_idx = Some(syn::Index::from(idx)); + } else { + throw_span_err!( + info.span.unwrap(), + "type of field annotated with `#[suggestion(...)]` contains more \ + than one Applicability" + ); + } + } + } + + if let Some(span_idx) = span_idx { + let binding = &info.binding.binding; + let span = quote!(#binding.#span_idx); + let applicability = applicability_idx + .map(|applicability_idx| quote!(#binding.#applicability_idx)) + .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); + + return Ok((span, Some(applicability))); + } + + throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| { + diag.help( + "`#[suggestion(...)]` on a tuple field must be applied to fields of type \ + `(Span, Applicability)`", + ) + }); + } + // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error. + _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| { + diag.help( + "`#[suggestion(...)]` should be applied to fields of type `Span` or \ + `(Span, Applicability)`", + ) + }), + } + } +} diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs index fd1dc2f307397..0b1ededa77510 100644 --- a/compiler/rustc_macros/src/diagnostics/error.rs +++ b/compiler/rustc_macros/src/diagnostics/error.rs @@ -4,16 +4,16 @@ use quote::quote; use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta}; #[derive(Debug)] -pub(crate) enum SessionDiagnosticDeriveError { +pub(crate) enum DiagnosticDeriveError { SynError(SynError), ErrorHandled, } -impl SessionDiagnosticDeriveError { +impl DiagnosticDeriveError { pub(crate) fn to_compile_error(self) -> TokenStream { match self { - SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(), - SessionDiagnosticDeriveError::ErrorHandled => { + DiagnosticDeriveError::SynError(e) => e.to_compile_error(), + DiagnosticDeriveError::ErrorHandled => { // Return ! to avoid having to create a blank DiagnosticBuilder to return when an // error has already been emitted to the compiler. quote! { @@ -24,9 +24,9 @@ impl SessionDiagnosticDeriveError { } } -impl From<SynError> for SessionDiagnosticDeriveError { +impl From<SynError> for DiagnosticDeriveError { fn from(e: SynError) -> Self { - SessionDiagnosticDeriveError::SynError(e) + DiagnosticDeriveError::SynError(e) } } @@ -34,9 +34,22 @@ impl From<SynError> for SessionDiagnosticDeriveError { pub(crate) fn _throw_err( diag: Diagnostic, f: impl FnOnce(Diagnostic) -> Diagnostic, -) -> SessionDiagnosticDeriveError { +) -> DiagnosticDeriveError { f(diag).emit(); - SessionDiagnosticDeriveError::ErrorHandled + DiagnosticDeriveError::ErrorHandled +} + +/// Helper function for printing `syn::Path` - doesn't handle arguments in paths and these are +/// unlikely to come up much in use of the macro. +fn path_to_string(path: &syn::Path) -> String { + let mut out = String::new(); + for (i, segment) in path.segments.iter().enumerate() { + if i > 0 || path.leading_colon.is_some() { + out.push_str("::"); + } + out.push_str(&segment.ident.to_string()); + } + out } /// Returns an error diagnostic on span `span` with msg `msg`. @@ -47,7 +60,7 @@ pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic { /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`. /// -/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`: +/// For methods that return a `Result<_, DiagnosticDeriveError>`: macro_rules! throw_span_err { ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }}; ($span:expr, $msg:expr, $f:expr) => {{ @@ -61,22 +74,20 @@ pub(crate) use throw_span_err; /// Returns an error diagnostic for an invalid attribute. pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic { let span = attr.span().unwrap(); - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - + let path = path_to_string(&attr.path); match meta { - Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", name)), + Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", path)), Meta::NameValue(_) => { - span_err(span, &format!("`#[{} = ...]` is not a valid attribute", name)) + span_err(span, &format!("`#[{} = ...]` is not a valid attribute", path)) } - Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", name)), + Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", path)), } } /// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`. /// -/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`: +/// For methods that return a `Result<_, DiagnosticDeriveError>`: macro_rules! throw_invalid_attr { ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }}; ($attr:expr, $meta:expr, $f:expr) => {{ @@ -101,18 +112,16 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag }; let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); + let path = path_to_string(meta.path()); match meta { - Meta::NameValue(..) => span_err( - span, - &format!("`#[{}({} = ...)]` is not a valid attribute", name, nested_name), - ), + Meta::NameValue(..) => { + span_err(span, &format!("`#[{}({} = ...)]` is not a valid attribute", name, path)) + } Meta::Path(..) => { - span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, nested_name)) + span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, path)) } Meta::List(..) => { - span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, nested_name)) + span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, path)) } } } @@ -120,7 +129,7 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag /// Emit a error diagnostic for an invalid nested attribute (optionally performing additional /// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`. /// -/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`: +/// For methods that return a `Result<_, DiagnosticDeriveError>`: macro_rules! throw_invalid_nested_attr { ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }}; ($attr:expr, $nested_attr:expr, $f:expr) => {{ diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 42a9bf477a41c..1170d2b3c59a4 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -189,9 +189,13 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry { let _ = previous_defns.entry(name.to_string()).or_insert(ident_span); - // `typeck-foo-bar` => `foo_bar` + // `typeck-foo-bar` => `foo_bar` (in `typeck.ftl`) + // `const-eval-baz` => `baz` (in `const_eval.ftl`) let snake_name = Ident::new( - &name.replace(&format!("{}-", res.ident), "").replace("-", "_"), + // FIXME: should probably trim prefix, not replace all occurrences + &name + .replace(&format!("{}-", res.ident).replace("_", "-"), "") + .replace("-", "_"), span, ); constants.extend(quote! { @@ -254,6 +258,19 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok ]; #generated + + pub mod _subdiag { + pub const help: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help")); + pub const note: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note")); + pub const warn: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn")); + pub const label: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label")); + pub const suggestion: crate::SubdiagnosticMessage = + crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion")); + } } } .into() diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 69573d904d4a9..3997900266641 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -1,10 +1,11 @@ mod diagnostic; +mod diagnostic_builder; mod error; mod fluent; mod subdiagnostic; mod utils; -use diagnostic::SessionDiagnosticDerive; +use diagnostic::{LintDiagnosticDerive, SessionDiagnosticDerive}; pub(crate) use fluent::fluent_messages; use proc_macro2::TokenStream; use quote::format_ident; @@ -22,14 +23,14 @@ use synstructure::Structure; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(SessionDiagnostic)] -/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")] +/// #[error(borrowck::move_out_of_borrow, code = "E0505")] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, /// #[primary_span] /// #[label] /// pub span: Span, -/// #[label = "first-borrow-label"] +/// #[label(borrowck::first_borrow_label)] /// pub first_borrow_span: Span, /// #[suggestion(code = "{name}.clone()")] /// pub clone_sugg: Option<(Span, Applicability)> @@ -56,13 +57,55 @@ use synstructure::Structure; /// ``` /// /// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`: -/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html> +/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html> pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { - // Names for the diagnostic we build and the session we build it from. - let diag = format_ident!("diag"); - let sess = format_ident!("sess"); + SessionDiagnosticDerive::new(format_ident!("diag"), format_ident!("sess"), s).into_tokens() +} - SessionDiagnosticDerive::new(diag, sess, s).into_tokens() +/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct, +/// independent from the actual lint emitting code. +/// +/// ```ignore (rust) +/// #[derive(LintDiagnostic)] +/// #[lint(lint::atomic_ordering_invalid_fail_success)] +/// pub struct AtomicOrderingInvalidLint { +/// method: Symbol, +/// success_ordering: Symbol, +/// fail_ordering: Symbol, +/// #[label(lint::fail_label)] +/// fail_order_arg_span: Span, +/// #[label(lint::success_label)] +/// #[suggestion( +/// code = "std::sync::atomic::Ordering::{success_suggestion}", +/// applicability = "maybe-incorrect" +/// )] +/// success_order_arg_span: Span, +/// } +/// ``` +/// +/// ```fluent +/// lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering +/// .fail-label = `{$fail_ordering}` failure ordering +/// .success-label = `{$success_ordering}` success ordering +/// .suggestion = consider using `{$success_suggestion}` success ordering instead +/// ``` +/// +/// Then, later, to emit the error: +/// +/// ```ignore (rust) +/// cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint { +/// method, +/// success_ordering, +/// fail_ordering, +/// fail_order_arg_span, +/// success_order_arg_span, +/// }); +/// ``` +/// +/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`: +/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html> +pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { + LintDiagnosticDerive::new(format_ident!("diag"), s).into_tokens() } /// Implements `#[derive(SessionSubdiagnostic)]`, which allows for labels, notes, helps and @@ -72,12 +115,12 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ```ignore (rust) /// #[derive(SessionSubdiagnostic)] /// pub enum ExpectedIdentifierLabel<'tcx> { -/// #[label(slug = "parser-expected-identifier")] +/// #[label(parser::expected_identifier)] /// WithoutFound { /// #[primary_span] /// span: Span, /// } -/// #[label(slug = "parser-expected-identifier-found")] +/// #[label(parser::expected_identifier_found)] /// WithFound { /// #[primary_span] /// span: Span, @@ -86,7 +129,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// } /// /// #[derive(SessionSubdiagnostic)] -/// #[suggestion_verbose(slug = "parser-raw-identifier")] +/// #[suggestion_verbose(parser::raw_identifier)] /// pub struct RawIdentifierSuggestion<'tcx> { /// #[primary_span] /// span: Span, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 9aeb484bfd52d..edf4dbed9853e 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -1,8 +1,7 @@ #![deny(unused_must_use)] use crate::diagnostics::error::{ - span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, - SessionDiagnosticDeriveError, + span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError, }; use crate::diagnostics::utils::{ report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, @@ -13,7 +12,7 @@ use quote::{format_ident, quote}; use std::collections::HashMap; use std::fmt; use std::str::FromStr; -use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue}; +use syn::{parse_quote, spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; /// Which kind of suggestion is being created? @@ -38,6 +37,8 @@ enum SubdiagnosticKind { Note, /// `#[help(...)]` Help, + /// `#[warn_(...)]` + Warn, /// `#[suggestion{,_short,_hidden,_verbose}]` Suggestion(SubdiagnosticSuggestionKind), } @@ -50,6 +51,7 @@ impl FromStr for SubdiagnosticKind { "label" => Ok(SubdiagnosticKind::Label), "note" => Ok(SubdiagnosticKind::Note), "help" => Ok(SubdiagnosticKind::Help), + "warn_" => Ok(SubdiagnosticKind::Warn), "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)), "suggestion_short" => { Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short)) @@ -71,6 +73,7 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Label => write!(f, "label"), SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), + SubdiagnosticKind::Warn => write!(f, "warn"), SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => { write!(f, "suggestion") } @@ -194,8 +197,8 @@ struct SessionSubdiagnosticDeriveBuilder<'a> { kind: Option<(SubdiagnosticKind, proc_macro::Span)>, /// Slug of the subdiagnostic - corresponds to the Fluent identifier for the message - from the - /// `#[kind(slug = "...")]` attribute on the type or variant. - slug: Option<(String, proc_macro::Span)>, + /// `#[kind(slug)]` attribute on the type or variant. + slug: Option<(Path, proc_macro::Span)>, /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]` /// attribute on the type or variant. code: Option<(TokenStream, proc_macro::Span)>, @@ -214,7 +217,7 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { } impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { - fn identify_kind(&mut self) -> Result<(), SessionDiagnosticDeriveError> { + fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> { for attr in self.variant.ast().attrs { let span = attr.span().unwrap(); @@ -224,9 +227,34 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { let meta = attr.parse_meta()?; let kind = match meta { Meta::List(MetaList { ref nested, .. }) => { - for nested_attr in nested { + let mut nested_iter = nested.into_iter(); + if let Some(nested_attr) = nested_iter.next() { + match nested_attr { + NestedMeta::Meta(Meta::Path(path)) => { + self.slug.set_once((path.clone(), span)); + } + NestedMeta::Meta(meta @ Meta::NameValue(_)) + if matches!( + meta.path().segments.last().unwrap().ident.to_string().as_str(), + "code" | "applicability" + ) => + { + // don't error for valid follow-up attributes + } + nested_attr => { + throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "first argument of the attribute should be the diagnostic \ + slug", + ) + }) + } + }; + } + + for nested_attr in nested_iter { let meta = match nested_attr { - syn::NestedMeta::Meta(ref meta) => meta, + NestedMeta::Meta(ref meta) => meta, _ => throw_invalid_nested_attr!(attr, &nested_attr), }; @@ -241,7 +269,6 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { let formatted_str = self.build_format(&s.value(), s.span()); self.code.set_once((formatted_str, span)); } - "slug" => self.slug.set_once((s.value(), span)), "applicability" => { let value = match Applicability::from_str(&s.value()) { Ok(v) => v, @@ -253,11 +280,23 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { self.applicability.set_once((quote! { #value }, span)); } _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help("only `code`, `slug` and `applicability` are valid nested attributes") + diag.help( + "only `code` and `applicability` are valid nested \ + attributes", + ) }), } } - _ => throw_invalid_nested_attr!(attr, &nested_attr), + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + if matches!(meta, Meta::Path(_)) { + diag.help( + "a diagnostic slug must be the first argument to the \ + attribute", + ) + } else { + diag + } + }), } } @@ -281,10 +320,27 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { ); } + if matches!( + kind, + SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note + ) && self.applicability.is_some() + { + throw_span_err!( + span, + &format!( + "`applicability` is not a valid nested attribute of a `{}` attribute", + name + ) + ); + } + if self.slug.is_none() { throw_span_err!( span, - &format!("`slug` must be set in a `#[{}(...)]` attribute", name) + &format!( + "diagnostic slug must be first argument of a `#[{}(...)]` attribute", + name + ) ); } @@ -298,7 +354,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { &mut self, binding: &BindingInfo<'_>, is_suggestion: bool, - ) -> Result<TokenStream, SessionDiagnosticDeriveError> { + ) -> Result<TokenStream, DiagnosticDeriveError> { let ast = binding.ast(); let inner_ty = FieldInnerTy::from_type(&ast.ty); @@ -335,7 +391,10 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { return Ok(quote! {}); } _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help("only `primary_span`, `applicability` and `skip_arg` are valid field attributes") + diag.help( + "only `primary_span`, `applicability` and `skip_arg` are valid field \ + attributes", + ) }), }, _ => throw_invalid_attr!(attr, &meta), @@ -355,7 +414,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { Ok(inner_ty.with(binding, generated)) } - fn into_tokens(&mut self) -> Result<TokenStream, SessionDiagnosticDeriveError> { + fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> { self.identify_kind()?; let Some(kind) = self.kind.map(|(kind, _)| kind) else { throw_span_err!( @@ -375,7 +434,11 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { } // Missing slug errors will already have been reported. - let slug = self.slug.as_ref().map(|(slug, _)| &**slug).unwrap_or("missing-slug"); + let slug = self + .slug + .as_ref() + .map(|(slug, _)| slug.clone()) + .unwrap_or_else(|| parse_quote! { you::need::to::specify::a::slug }); let code = match self.code.as_ref() { Some((code, _)) => Some(quote! { #code }), None if is_suggestion => { @@ -397,7 +460,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { let diag = &self.diag; let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::SubdiagnosticMessage::message(#slug) }; + let message = quote! { rustc_errors::fluent::#slug }; let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) { if let Some(span) = span_field { quote! { #diag.#name(#span, #message, #code, #applicability); } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 636bcf1f7b1d9..002abb152f759 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -1,11 +1,11 @@ -use crate::diagnostics::error::{span_err, throw_span_err, SessionDiagnosticDeriveError}; +use crate::diagnostics::error::{span_err, throw_span_err, DiagnosticDeriveError}; use proc_macro::Span; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; -use std::collections::BTreeSet; +use std::collections::{BTreeSet, HashMap}; use std::str::FromStr; use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple}; -use synstructure::BindingInfo; +use synstructure::{BindingInfo, Structure}; /// Checks whether the type name of `ty` matches `name`. /// @@ -34,7 +34,7 @@ pub(crate) fn type_is_unit(ty: &Type) -> bool { pub(crate) fn report_type_error( attr: &Attribute, ty_name: &str, -) -> Result<!, SessionDiagnosticDeriveError> { +) -> Result<!, DiagnosticDeriveError> { let name = attr.path.segments.last().unwrap().ident.to_string(); let meta = attr.parse_meta()?; @@ -59,7 +59,7 @@ fn report_error_if_not_applied_to_ty( info: &FieldInfo<'_>, path: &[&str], ty_name: &str, -) -> Result<(), SessionDiagnosticDeriveError> { +) -> Result<(), DiagnosticDeriveError> { if !type_matches_path(&info.ty, path) { report_type_error(attr, ty_name)?; } @@ -71,7 +71,7 @@ fn report_error_if_not_applied_to_ty( pub(crate) fn report_error_if_not_applied_to_applicability( attr: &Attribute, info: &FieldInfo<'_>, -) -> Result<(), SessionDiagnosticDeriveError> { +) -> Result<(), DiagnosticDeriveError> { report_error_if_not_applied_to_ty( attr, info, @@ -84,8 +84,14 @@ pub(crate) fn report_error_if_not_applied_to_applicability( pub(crate) fn report_error_if_not_applied_to_span( attr: &Attribute, info: &FieldInfo<'_>, -) -> Result<(), SessionDiagnosticDeriveError> { - report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`") +) -> Result<(), DiagnosticDeriveError> { + if !type_matches_path(&info.ty, &["rustc_span", "Span"]) + && !type_matches_path(&info.ty, &["rustc_errors", "MultiSpan"]) + { + report_type_error(attr, "`Span` or `MultiSpan`")?; + } + + Ok(()) } /// Inner type of a field and type of wrapper. @@ -166,10 +172,12 @@ pub(crate) struct FieldInfo<'a> { /// Small helper trait for abstracting over `Option` fields that contain a value and a `Span` /// for error reporting if they are set more than once. pub(crate) trait SetOnce<T> { - fn set_once(&mut self, value: T); + fn set_once(&mut self, _: (T, Span)); + + fn value(self) -> Option<T>; } -impl<T> SetOnce<(T, Span)> for Option<(T, Span)> { +impl<T> SetOnce<T> for Option<(T, Span)> { fn set_once(&mut self, (value, span): (T, Span)) { match self { None => { @@ -182,6 +190,10 @@ impl<T> SetOnce<(T, Span)> for Option<(T, Span)> { } } } + + fn value(self) -> Option<T> { + self.map(|(v, _)| v) + } } pub(crate) trait HasFieldMap { @@ -325,3 +337,20 @@ impl quote::ToTokens for Applicability { }); } } + +/// Build the mapping of field names to fields. This allows attributes to peek values from +/// other fields. +pub(crate) fn build_field_mapping<'a>(structure: &Structure<'a>) -> HashMap<String, TokenStream> { + let mut fields_map = HashMap::new(); + + let ast = structure.ast(); + if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data { + for field in fields.iter() { + if let Some(ident) = &field.ident { + fields_map.insert(ident.to_string(), quote! { &self.#ident }); + } + } + } + + fields_map +} diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 7c8e3c6d14024..ab509b26f1c55 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -18,6 +18,7 @@ mod query; mod serialize; mod symbols; mod type_foldable; +mod type_visitable; #[proc_macro] pub fn rustc_queries(input: TokenStream) -> TokenStream { @@ -121,14 +122,17 @@ decl_derive!([TyEncodable] => serialize::type_encodable_derive); decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive); +decl_derive!([TypeVisitable, attributes(type_visitable)] => type_visitable::type_visitable_derive); decl_derive!([Lift, attributes(lift)] => lift::lift_derive); decl_derive!( [SessionDiagnostic, attributes( // struct attributes warning, error, - note, + lint, help, + note, + warn_, // field attributes skip_arg, primary_span, @@ -139,12 +143,32 @@ decl_derive!( suggestion_hidden, suggestion_verbose)] => diagnostics::session_diagnostic_derive ); +decl_derive!( + [LintDiagnostic, attributes( + // struct attributes + warning, + error, + lint, + help, + note, + warn_, + // field attributes + skip_arg, + primary_span, + label, + subdiagnostic, + suggestion, + suggestion_short, + suggestion_hidden, + suggestion_verbose)] => diagnostics::lint_diagnostic_derive +); decl_derive!( [SessionSubdiagnostic, attributes( // struct/variant attributes label, help, note, + warn_, suggestion, suggestion_short, suggestion_hidden, diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 9e834d3ba1c2d..23e619221aab7 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -11,11 +11,6 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: } s.add_bounds(synstructure::AddBounds::Generics); - let body_visit = s.each(|bind| { - quote! { - ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?; - } - }); s.bind_with(|_| synstructure::BindStyle::Move); let body_fold = s.each_variant(|vi| { let bindings = vi.bindings(); @@ -36,14 +31,6 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: ) -> Result<Self, __F::Error> { Ok(match self { #body_fold }) } - - fn visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( - &self, - __folder: &mut __F - ) -> ::std::ops::ControlFlow<__F::BreakTy> { - match *self { #body_visit } - ::std::ops::ControlFlow::CONTINUE - } }, ) } diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs new file mode 100644 index 0000000000000..14e6aa6e0c17b --- /dev/null +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -0,0 +1,33 @@ +use quote::quote; +use syn::parse_quote; + +pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { + s.add_impl_generic(parse_quote! { 'tcx }); + } + + s.add_bounds(synstructure::AddBounds::Generics); + let body_visit = s.each(|bind| { + quote! { + ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?; + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); + + s.bound_impl( + quote!(::rustc_middle::ty::visit::TypeVisitable<'tcx>), + quote! { + fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<'tcx>>( + &self, + __visitor: &mut __V + ) -> ::std::ops::ControlFlow<__V::BreakTy> { + match *self { #body_visit } + ::std::ops::ControlFlow::CONTINUE + } + }, + ) +} diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 41224e3346177..2c5db9d8b2765 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -11,7 +11,8 @@ libloading = "0.7.1" odht = { version = "0.3.1", features = ["nightly"] } snap = "1" tracing = "0.1" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } +tempfile = "3.2" rustc_middle = { path = "../rustc_middle" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 555db5846edd0..708d0b1fd8a30 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -456,7 +456,7 @@ impl<'a> CrateLoader<'a> { proc_macro_locator.is_proc_macro = true; // Load the proc macro crate for the target - let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros { + let (locator, target_result) = if self.sess.opts.unstable_opts.dual_proc_macros { proc_macro_locator.reset(); let result = match self.load(&mut proc_macro_locator)? { Some(LoadResult::Previous(cnum)) => { @@ -485,7 +485,7 @@ impl<'a> CrateLoader<'a> { return Ok(None); }; - Ok(Some(if self.sess.opts.debugging_opts.dual_proc_macros { + Ok(Some(if self.sess.opts.unstable_opts.dual_proc_macros { let host_result = match host_result { LoadResult::Previous(..) => { panic!("host and target proc macros must be loaded in lock-step") @@ -748,7 +748,7 @@ impl<'a> CrateLoader<'a> { if !data.is_panic_runtime() { self.sess.err(&format!("the crate `{}` is not a panic runtime", name)); } - if data.panic_strategy() != desired_strategy { + if data.required_panic_strategy() != Some(desired_strategy) { self.sess.err(&format!( "the crate `{}` does not have the panic \ strategy `{}`", @@ -762,9 +762,9 @@ impl<'a> CrateLoader<'a> { } fn inject_profiler_runtime(&mut self, krate: &ast::Crate) { - if self.sess.opts.debugging_opts.no_profiler_runtime + if self.sess.opts.unstable_opts.no_profiler_runtime || !(self.sess.instrument_coverage() - || self.sess.opts.debugging_opts.profile + || self.sess.opts.unstable_opts.profile || self.sess.opts.cg.profile_generate.enabled()) { return; @@ -772,7 +772,7 @@ impl<'a> CrateLoader<'a> { info!("loading profiler"); - let name = Symbol::intern(&self.sess.opts.debugging_opts.profiler_runtime); + 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) { self.sess.err( "`profiler_builtins` crate (required by compiler options) \ diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 245b2076ebca9..b765c34f8e364 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -60,7 +60,6 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use rustc_session::cstore::CrateDepKind; use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; -use rustc_target::spec::PanicStrategy; pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies { tcx.sess @@ -367,14 +366,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { prev_name, cur_name )); } - panic_runtime = Some((cnum, tcx.panic_strategy(cnum))); + panic_runtime = Some(( + cnum, + tcx.required_panic_strategy(cnum).unwrap_or_else(|| { + bug!("cannot determine panic strategy of a panic runtime"); + }), + )); } } // If we found a panic runtime, then we know by this point that it's the // only one, but we perform validation here that all the panic strategy // compilation modes for the whole DAG are valid. - if let Some((cnum, found_strategy)) = panic_runtime { + if let Some((runtime_cnum, found_strategy)) = panic_runtime { let desired_strategy = sess.panic_strategy(); // First up, validate that our selected panic runtime is indeed exactly @@ -384,7 +388,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { "the linked panic runtime `{}` is \ not compiled with this crate's \ panic strategy `{}`", - tcx.crate_name(cnum), + tcx.crate_name(runtime_cnum), desired_strategy.desc() )); } @@ -397,18 +401,14 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { if let Linkage::NotLinked = *linkage { continue; } - if desired_strategy == PanicStrategy::Abort { - continue; - } let cnum = CrateNum::new(i + 1); - if tcx.is_compiler_builtins(cnum) { + if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) { continue; } - let found_strategy = tcx.panic_strategy(cnum); - if desired_strategy != found_strategy { + if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy { sess.err(&format!( - "the crate `{}` is compiled with the \ + "the crate `{}` requires \ panic strategy `{}` which is \ incompatible with this crate's \ strategy of `{}`", @@ -419,7 +419,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { } let found_drop_strategy = tcx.panic_in_drop_strategy(cnum); - if tcx.sess.opts.debugging_opts.panic_in_drop != found_drop_strategy { + if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy { sess.err(&format!( "the crate `{}` is compiled with the \ panic-in-drop strategy `{}` which is \ @@ -427,7 +427,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { strategy of `{}`", tcx.crate_name(cnum), found_drop_strategy.desc(), - tcx.sess.opts.debugging_opts.panic_in_drop.desc() + tcx.sess.opts.unstable_opts.panic_in_drop.desc() )); } } diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs new file mode 100644 index 0000000000000..e6072901aaa43 --- /dev/null +++ b/compiler/rustc_metadata/src/fs.rs @@ -0,0 +1,137 @@ +use crate::{encode_metadata, EncodedMetadata}; + +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::{CrateType, OutputFilenames, OutputType}; +use rustc_session::output::filename_for_metadata; +use rustc_session::Session; +use tempfile::Builder as TempFileBuilder; + +use std::fs; +use std::path::{Path, PathBuf}; + +// FIXME(eddyb) maybe include the crate name in this? +pub const METADATA_FILENAME: &str = "lib.rmeta"; + +/// We use a temp directory here to avoid races between concurrent rustc processes, +/// such as builds in the same directory using the same filename for metadata while +/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a +/// directory being searched for `extern crate` (observing an incomplete file). +/// The returned path is the temporary file containing the complete metadata. +pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf { + let out_filename = tmpdir.as_ref().join(METADATA_FILENAME); + let result = fs::write(&out_filename, metadata); + + if let Err(e) = result { + sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + + out_filename +} + +pub fn encode_and_write_metadata( + tcx: TyCtxt<'_>, + outputs: &OutputFilenames, +) -> (EncodedMetadata, bool) { + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum MetadataKind { + None, + Uncompressed, + Compressed, + } + + let metadata_kind = tcx + .sess + .crate_types() + .iter() + .map(|ty| match *ty { + CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None, + + CrateType::Rlib => MetadataKind::Uncompressed, + + CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed, + }) + .max() + .unwrap_or(MetadataKind::None); + + let crate_name = tcx.crate_name(LOCAL_CRATE); + let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs); + // To avoid races with another rustc process scanning the output directory, + // we need to write the file somewhere else and atomically move it to its + // final destination, with an `fs::rename` call. In order for the rename to + // always succeed, the temporary file needs to be on the same filesystem, + // which is why we create it inside the output directory specifically. + let metadata_tmpdir = TempFileBuilder::new() + .prefix("rmeta") + .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new(""))) + .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); + let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); + let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME); + + // Always create a file at `metadata_filename`, even if we have nothing to write to it. + // This simplifies the creation of the output `out_filename` when requested. + match metadata_kind { + MetadataKind::None => { + std::fs::File::create(&metadata_filename).unwrap_or_else(|e| { + tcx.sess.fatal(&format!( + "failed to create the file {}: {}", + metadata_filename.display(), + e + )) + }); + } + MetadataKind::Uncompressed | MetadataKind::Compressed => { + encode_metadata(tcx, &metadata_filename); + } + }; + + let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); + + // If the user requests metadata as output, rename `metadata_filename` + // to the expected output `out_filename`. The match above should ensure + // this file always exists. + let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); + let (metadata_filename, metadata_tmpdir) = if need_metadata_file { + if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) { + tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + if tcx.sess.opts.json_artifact_notifications { + tcx.sess + .parse_sess + .span_diagnostic + .emit_artifact_notification(&out_filename, "metadata"); + } + (out_filename, None) + } else { + (metadata_filename, Some(metadata_tmpdir)) + }; + + // Load metadata back to memory: codegen may need to include it in object files. + let metadata = + EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| { + tcx.sess.fatal(&format!("failed to create encoded metadata from file: {}", e)) + }); + + let need_metadata_module = metadata_kind == MetadataKind::Compressed; + + (metadata, need_metadata_module) +} + +#[cfg(not(target_os = "linux"))] +pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> { + std::fs::rename(src, dst) +} + +/// This function attempts to bypass the auto_da_alloc heuristic implemented by some filesystems +/// such as btrfs and ext4. When renaming over a file that already exists then they will "helpfully" +/// write back the source file before committing the rename in case a developer forgot some of +/// the fsyncs in the open/write/fsync(file)/rename/fsync(dir) dance for atomic file updates. +/// +/// To avoid triggering this heuristic we delete the destination first, if it exists. +/// The cost of an extra syscall is much lower than getting descheduled for the sync IO. +#[cfg(target_os = "linux")] +pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> { + let _ = std::fs::remove_file(dst); + std::fs::rename(src, dst) +} diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 5ad16398695b2..e192378bcc3d2 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -4,7 +4,7 @@ #![feature(generators)] #![feature(generic_associated_types)] #![feature(iter_from_generator)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(once_cell)] #![feature(proc_macro_internals)] @@ -34,6 +34,8 @@ mod native_libs; mod rmeta; pub mod creader; +pub mod fs; pub mod locator; +pub use fs::{emit_metadata, METADATA_FILENAME}; pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER}; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index dbe53224e2aaa..a72bcb9a2dbd1 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -1179,7 +1179,7 @@ impl CrateError { err.help("consider building the standard library from source with `cargo build -Zbuild-std`"); } } else if crate_name - == Symbol::intern(&sess.opts.debugging_opts.profiler_runtime) + == Symbol::intern(&sess.opts.unstable_opts.profiler_runtime) { err.note("the compiler may have been built without the profiler runtime"); } else if crate_name.as_str().starts_with("rustc_") { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index c1ded99a25af5..f0874f8f2da00 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -21,7 +21,6 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::GeneratorDiagnosticData; @@ -42,7 +41,7 @@ use std::io; use std::iter::TrustedLen; use std::mem; use std::num::NonZeroUsize; -use std::path::Path; +use std::path::PathBuf; use tracing::debug; pub(super) use cstore_impl::provide; @@ -638,7 +637,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { } } -impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [ty::abstract_const::Node<'tcx>] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) } @@ -1473,20 +1472,26 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // // NOTE: if you update this, you might need to also update bootstrap's code for generating // the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`. - let virtual_rust_source_base_dir = option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR") - .map(Path::new) - .filter(|_| { - // Only spend time on further checks if we have what to translate *to*. - sess.opts.real_rust_source_base_dir.is_some() - // Some tests need the translation to be always skipped. - && sess.opts.debugging_opts.translate_remapped_path_to_local_path - }) - .filter(|virtual_dir| { - // Don't translate away `/rustc/$hash` if we're still remapping to it, - // since that means we're still building `std`/`rustc` that need it, - // and we don't want the real path to leak into codegen/debuginfo. - !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir) - }); + let virtual_rust_source_base_dir = [ + option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from), + sess.opts.unstable_opts.simulate_remapped_rust_src_base.clone(), + ] + .into_iter() + .filter(|_| { + // Only spend time on further checks if we have what to translate *to*. + sess.opts.real_rust_source_base_dir.is_some() + // Some tests need the translation to be always skipped. + && sess.opts.unstable_opts.translate_remapped_path_to_local_path + }) + .flatten() + .filter(|virtual_dir| { + // Don't translate away `/rustc/$hash` if we're still remapping to it, + // since that means we're still building `std`/`rustc` that need it, + // and we don't want the real path to leak into codegen/debuginfo. + !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir) + }) + .collect::<Vec<_>>(); + let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| { debug!( "try_to_translate_virtual_to_real(name={:?}): \ @@ -1494,7 +1499,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir, ); - if let Some(virtual_dir) = virtual_rust_source_base_dir { + for virtual_dir in &virtual_rust_source_base_dir { if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { if let rustc_span::FileName::Real(old_name) = name { if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = @@ -1578,7 +1583,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // `try_to_translate_virtual_to_real` don't have to worry about how the // compiler is bootstrapped. if let Some(virtual_dir) = - &sess.opts.debugging_opts.simulate_remapped_rust_src_base + &sess.opts.unstable_opts.simulate_remapped_rust_src_base { if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { if let rustc_span::FileName::Real(ref mut old_name) = name { @@ -1752,8 +1757,8 @@ impl CrateMetadata { self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind)) } - pub(crate) fn panic_strategy(&self) -> PanicStrategy { - self.root.panic_strategy + pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> { + self.root.required_panic_strategy } pub(crate) fn needs_panic_runtime(&self) -> bool { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0bea2a10da896..565eec18ea9b8 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -246,7 +246,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, has_global_allocator => { cdata.root.has_global_allocator } has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } - panic_strategy => { cdata.root.panic_strategy } + required_panic_strategy => { cdata.root.required_panic_strategy } panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy } extern_crate => { let r = *cdata.extern_crate.lock(); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 75286b8906871..8e97300977723 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -4,8 +4,10 @@ use crate::rmeta::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; +use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{ @@ -27,8 +29,7 @@ use rustc_middle::ty::codec::TyEncoder; 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_serialize::opaque::MemEncoder; -use rustc_serialize::{Encodable, Encoder}; +use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; @@ -39,12 +40,14 @@ use rustc_span::{ use rustc_target::abi::VariantIdx; use std::borrow::Borrow; use std::hash::Hash; +use std::io::{Read, Seek, Write}; use std::iter; use std::num::NonZeroUsize; +use std::path::{Path, PathBuf}; use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { - opaque: MemEncoder, + opaque: opaque::FileEncoder, tcx: TyCtxt<'tcx>, feat: &'tcx rustc_feature::Features, @@ -419,11 +422,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - self.tcx.hir().deep_visit_all_item_likes(self); + self.tcx.hir().visit_all_item_likes_in_crate(self); } fn encode_def_path_table(&mut self) { - let table = self.tcx.definitions_untracked().def_path_table(); + let table = self.tcx.def_path_table(); if self.is_proc_macro { for def_index in std::iter::once(CRATE_DEF_INDEX) .chain(self.tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index)) @@ -443,9 +446,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_def_path_hash_map(&mut self) -> LazyValue<DefPathHashMapRef<'static>> { - self.lazy(DefPathHashMapRef::BorrowedFromTcx( - self.tcx.definitions_untracked().def_path_hash_to_def_index_map(), - )) + self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map())) } fn encode_source_map(&mut self) -> LazyArray<rustc_span::SourceFile> { @@ -614,7 +615,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let interpret_alloc_index_bytes = self.position() - i; // Encode the proc macro data. This affects 'tables', - // so we need to do this before we encode the tables + // so we need to do this before we encode the tables. + // This overwrites def_keys, so it must happen after encode_def_path_table. i = self.position(); let proc_macro_data = self.encode_proc_macros(); let proc_macro_data_bytes = self.position() - i; @@ -665,8 +667,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { triple: tcx.sess.opts.target_triple.clone(), hash: tcx.crate_hash(LOCAL_CRATE), stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), - panic_strategy: tcx.sess.panic_strategy(), - panic_in_drop_strategy: tcx.sess.opts.debugging_opts.panic_in_drop, + required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE), + panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), @@ -730,12 +732,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert_eq!(total_bytes, computed_total_bytes); if tcx.sess.meta_stats() { + self.opaque.flush(); + + // Rewind and re-read all the metadata to count the zero bytes we wrote. + let pos_before_rewind = self.opaque.file().stream_position().unwrap(); let mut zero_bytes = 0; - for e in self.opaque.data.iter() { - if *e == 0 { + self.opaque.file().rewind().unwrap(); + let file = std::io::BufReader::new(self.opaque.file()); + for e in file.bytes() { + if e.unwrap() == 0 { zero_bytes += 1; } } + assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind); let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64; let p = |label, bytes| { @@ -863,7 +872,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { // Constructors DefKind::Ctor(_, _) => { let mir_opt_base = tcx.sess.opts.output_types.should_codegen() - || tcx.sess.opts.debugging_opts.always_encode_mir; + || tcx.sess.opts.unstable_opts.always_encode_mir; (true, mir_opt_base) } // Constants @@ -881,7 +890,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { // The function has a `const` modifier or is in a `#[const_trait]`. let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); - let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir; + let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; (is_const_fn, needs_inline || always_encode_mir) } // Closures can't be const fn. @@ -890,7 +899,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { let needs_inline = (generics.requires_monomorphization(tcx) || tcx.codegen_fn_attrs(def_id).requests_inline()) && tcx.sess.opts.output_types.should_codegen(); - let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir; + let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir; (false, needs_inline || always_encode_mir) } // Generators require optimized MIR to compute layout. @@ -992,8 +1001,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } let tcx = self.tcx; - let hir = tcx.hir(); - for local_id in hir.iter_local_def_id() { + for local_id in tcx.iter_local_def_id() { let def_id = local_id.to_def_id(); let def_kind = tcx.opt_def_kind(local_id); let Some(def_kind) = def_kind else { continue }; @@ -1362,7 +1370,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_stability(def_id) { record!(self.tables.lookup_stability[def_id] <- stab) } @@ -1374,7 +1382,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // The query lookup can take a measurable amount of time in crates with many items. Check if // the stability attributes are even enabled before using their queries. - if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if let Some(stab) = self.tcx.lookup_const_stability(def_id) { record!(self.tables.lookup_const_stability[def_id] <- stab) } @@ -1854,12 +1862,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); let tcx = self.tcx; - let mut ctx = tcx.create_stable_hashing_context(); let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect(); - all_impls.sort_by_cached_key(|&(&simp, _)| { - let mut hasher = StableHasher::new(); - simp.hash_stable(&mut ctx, &mut hasher); - hasher.finish::<Fingerprint>(); + tcx.with_stable_hashing_context(|mut ctx| { + all_impls.sort_by_cached_key(|&(&simp, _)| { + let mut hasher = StableHasher::new(); + simp.hash_stable(&mut ctx, &mut hasher); + hasher.finish::<Fingerprint>() + }) }); let all_impls: Vec<_> = all_impls .into_iter() @@ -2134,24 +2143,58 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { // will allow us to slice the metadata to the precise length that we just // generated regardless of trailing bytes that end up in it. -#[derive(Encodable, Decodable)] pub struct EncodedMetadata { - raw_data: Vec<u8>, + // The declaration order matters because `mmap` should be dropped before `_temp_dir`. + mmap: Option<Mmap>, + // We need to carry MaybeTempDir to avoid deleting the temporary + // directory while accessing the Mmap. + _temp_dir: Option<MaybeTempDir>, } impl EncodedMetadata { #[inline] - pub fn new() -> EncodedMetadata { - EncodedMetadata { raw_data: Vec::new() } + pub fn from_path(path: PathBuf, temp_dir: Option<MaybeTempDir>) -> std::io::Result<Self> { + let file = std::fs::File::open(&path)?; + let file_metadata = file.metadata()?; + if file_metadata.len() == 0 { + return Ok(Self { mmap: None, _temp_dir: None }); + } + let mmap = unsafe { Some(Mmap::map(file)?) }; + Ok(Self { mmap, _temp_dir: temp_dir }) } #[inline] pub fn raw_data(&self) -> &[u8] { - &self.raw_data + self.mmap.as_ref().map(|mmap| mmap.as_ref()).unwrap_or_default() + } +} + +impl<S: Encoder> Encodable<S> for EncodedMetadata { + fn encode(&self, s: &mut S) { + let slice = self.raw_data(); + slice.encode(s) } } -pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { +impl<D: Decoder> Decodable<D> for EncodedMetadata { + fn decode(d: &mut D) -> Self { + let len = d.read_usize(); + let mmap = if len > 0 { + let mut mmap = MmapMut::map_anon(len).unwrap(); + for _ in 0..len { + (&mut mmap[..]).write(&[d.read_u8()]).unwrap(); + } + mmap.flush().unwrap(); + Some(mmap.make_read_only().unwrap()) + } else { + None + }; + + Self { mmap, _temp_dir: None } + } +} + +pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata"); // Since encoding metadata is not in a query, and nothing is cached, @@ -2159,7 +2202,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { tcx.dep_graph.assert_ignored(); join( - || encode_metadata_impl(tcx), + || encode_metadata_impl(tcx, path), || { if tcx.sess.threads() == 1 { return; @@ -2169,12 +2212,12 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { // It can be removed if it turns out to cause trouble or be detrimental to performance. join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE)); }, - ) - .0 + ); } -fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { - let mut encoder = MemEncoder::new(); +fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { + let mut encoder = opaque::FileEncoder::new(path) + .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to create file encoder: {}", err))); encoder.emit_raw_bytes(METADATA_HEADER); // Will be filled with the root position after encoding everything. @@ -2209,20 +2252,29 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { // culminating in the `CrateRoot` which points to all of it. let root = ecx.encode_crate_root(); - let mut result = ecx.opaque.finish(); + ecx.opaque.flush(); + + let mut file = ecx.opaque.file(); + // We will return to this position after writing the root position. + let pos_before_seek = file.stream_position().unwrap(); // Encode the root position. let header = METADATA_HEADER.len(); + file.seek(std::io::SeekFrom::Start(header as u64)) + .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to seek the file: {}", err))); let pos = root.position.get(); - result[header + 0] = (pos >> 24) as u8; - result[header + 1] = (pos >> 16) as u8; - result[header + 2] = (pos >> 8) as u8; - result[header + 3] = (pos >> 0) as u8; + file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8]) + .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to write to the file: {}", err))); - // Record metadata size for self-profiling - tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64); + // Return to the position where we are before writing the root position. + file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap(); - EncodedMetadata { raw_data: result } + // Record metadata size for self-profiling + tcx.prof.artifact_size( + "crate_metadata", + "crate_metadata", + file.metadata().unwrap().len() as u64, + ); } pub fn provide(providers: &mut Providers) { @@ -2243,5 +2295,5 @@ pub fn provide(providers: &mut Providers) { }, ..*providers - }; + } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a58c0e68ee38c..af1c09f4ae87a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -17,12 +17,11 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::mir; -use rustc_middle::thir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; -use rustc_serialize::opaque::MemEncoder; +use rustc_serialize::opaque::FileEncoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; @@ -217,7 +216,7 @@ pub(crate) struct CrateRoot { extra_filename: String, hash: Svh, stable_crate_id: StableCrateId, - panic_strategy: PanicStrategy, + required_panic_strategy: Option<PanicStrategy>, panic_in_drop_strategy: PanicStrategy, edition: Edition, has_global_allocator: bool, @@ -323,7 +322,7 @@ macro_rules! define_tables { } impl TableBuilders { - fn encode(&self, buf: &mut MemEncoder) -> LazyTables { + fn encode(&self, buf: &mut FileEncoder) -> LazyTables { LazyTables { $($name: self.$name.encode(buf)),+ } @@ -361,7 +360,7 @@ define_tables! { mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, // FIXME(compiler-errors): Why isn't this a LazyArray? - thir_abstract_const: Table<DefIndex, LazyValue<&'static [thir::abstract_const::Node<'static>]>>, + thir_abstract_const: Table<DefIndex, LazyValue<&'static [ty::abstract_const::Node<'static>]>>, impl_parent: Table<DefIndex, RawDefId>, impl_polarity: Table<DefIndex, ty::ImplPolarity>, constness: Table<DefIndex, hir::Constness>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 5ab4269ae99ad..42759f0a652b3 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -4,8 +4,8 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def::{CtorKind, CtorOf}; use rustc_index::vec::Idx; use rustc_middle::ty::ParameterizedOverTcx; -use rustc_serialize::opaque::MemEncoder; -use rustc_serialize::Encoder; +use rustc_serialize::opaque::FileEncoder; +use rustc_serialize::Encoder as _; use rustc_span::hygiene::MacroKind; use std::convert::TryInto; use std::marker::PhantomData; @@ -281,7 +281,7 @@ where Some(value).write_to_bytes(&mut self.blocks[i]); } - pub(crate) fn encode<const N: usize>(&self, buf: &mut MemEncoder) -> LazyTable<I, T> + pub(crate) fn encode<const N: usize>(&self, buf: &mut FileEncoder) -> LazyTable<I, T> where Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>, { diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index cee80823443f5..008d2c7091c1e 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -30,7 +30,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } chalk-ir = "0.80.0" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_session = { path = "../rustc_session" } rustc_type_ir = { path = "../rustc_type_ir" } rand = "0.8.4" diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 984c95b314ba8..661a9b1944c58 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -96,6 +96,7 @@ macro_rules! arena_types { // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, + [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, [] dep_kind: rustc_middle::dep_graph::DepKindStruct, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 555baae35f506..2d095438fc4e9 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -183,6 +183,9 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> // We use this for most things when incr. comp. is turned off. [] Null, + // We use this to create a forever-red node. + [] Red, + [anon] TraitSelect, // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below. diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index e335cb395f84f..c8b3b52b0fb2b 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -23,6 +23,7 @@ pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; + const RED: Self = DepKind::Red; fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}(", node.kind)?; @@ -71,8 +72,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { type DepKind = DepKind; #[inline] - fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { - TyCtxt::create_stable_hashing_context(*self) + fn with_stable_hashing_context<R>(&self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R { + TyCtxt::with_stable_hashing_context(*self, f) } #[inline] diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 738d47ba29681..3a59b2069b3b7 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -22,7 +22,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl), - Node::Expr(Expr { kind: ExprKind::Closure { fn_decl, .. }, .. }) + Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => { Some(fn_decl) } @@ -39,6 +39,7 @@ pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> { } } +#[inline] pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> { match node { Node::Item(Item { @@ -54,7 +55,7 @@ pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> { kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), .. }) - | Node::Expr(Expr { kind: ExprKind::Closure { body, .. }, .. }) => Some(*body), + | Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body), Node::AnonConst(constant) => Some(constant.body), @@ -218,14 +219,8 @@ impl<'hir> Map<'hir> { self.tcx.local_def_id_to_hir_id(def_id) } - pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'hir { - // Create a dependency to the crate to be sure we re-execute this when the amount of - // definitions change. - self.tcx.ensure().hir_crate(()); - self.tcx.definitions_untracked().iter_local_def_id() - } - - pub fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> { + /// Do not call this function directly. The query should be called. + pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> { let hir_id = self.local_def_id_to_hir_id(local_def_id); let def_kind = match self.find(hir_id)? { Node::Item(item) => match item.kind { @@ -285,8 +280,8 @@ impl<'hir> Map<'hir> { } Node::Field(_) => DefKind::Field, Node::Expr(expr) => match expr.kind { - ExprKind::Closure { movability: None, .. } => DefKind::Closure, - ExprKind::Closure { movability: Some(_), .. } => DefKind::Generator, + ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure, + ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator, _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)), }, Node::GenericParam(param) => match param.kind { @@ -302,7 +297,6 @@ impl<'hir> Map<'hir> { | Node::Infer(_) | Node::TraitRef(_) | Node::Pat(_) - | Node::Binding(_) | Node::Local(_) | Node::Param(_) | Node::Arm(_) @@ -493,35 +487,13 @@ impl<'hir> Map<'hir> { /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { - self.krate() - .owners - .iter_enumerated() - .flat_map(move |(owner, owner_info)| { - let bodies = &owner_info.as_owner()?.nodes.bodies; - Some(bodies.iter().map(move |&(local_id, _)| { - let hir_id = HirId { owner, local_id }; - let body_id = BodyId { hir_id }; - self.body_owner_def_id(body_id) - })) - }) - .flatten() + self.tcx.hir_crate_items(()).body_owners.iter().copied() } pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) { use rustc_data_structures::sync::{par_iter, ParallelIterator}; - #[cfg(parallel_compiler)] - use rustc_rayon::iter::IndexedParallelIterator; - - par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| { - let owner = LocalDefId::new(owner); - if let MaybeOwner::Owner(owner_info) = owner_info { - par_iter(owner_info.nodes.bodies.range(..)).for_each(|(local_id, _)| { - let hir_id = HirId { owner, local_id: *local_id }; - let body_id = BodyId { hir_id }; - f(self.body_owner_def_id(body_id)) - }) - } - }); + + par_iter(&self.tcx.hir_crate_items(()).body_owners[..]).for_each(|&def_id| f(def_id)); } pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { @@ -568,7 +540,7 @@ impl<'hir> Map<'hir> { } } - /// Walks the contents of a crate. See also `Crate::visit_all_items`. + /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`. pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) { let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID); visitor.visit_mod(top_mod, span, hir_id); @@ -588,70 +560,61 @@ impl<'hir> Map<'hir> { } } - /// Visits all items in the crate in some deterministic (but - /// unspecified) order. If you need to process every item, - /// and care about nesting -- usually because your algorithm - /// follows lexical scoping rules -- then this method is the best choice. - /// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query - /// or `items()` instead. + /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you + /// need to process every item-like, and don't care about visiting nested items in a particular + /// order then this method is the best choice. If you do care about this nesting, you should + /// use the `tcx.hir().walk_toplevel_module`. + /// + /// Note that this function will access HIR for all the item-likes in the crate. If you only + /// need to access some of them, it is usually better to manually loop on the iterators + /// provided by `tcx.hir_crate_items(())`. /// /// Please see the notes in `intravisit.rs` for more information. - pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V) + pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V) where V: Visitor<'hir>, { - let krate = self.krate(); - for owner in krate.owners.iter().filter_map(|i| i.as_owner()) { - match owner.node() { - OwnerNode::Item(item) => visitor.visit_item(item), - OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), - OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), - OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), - OwnerNode::Crate(_) => {} - } + let krate = self.tcx.hir_crate_items(()); + + for id in krate.items() { + visitor.visit_item(self.item(id)); } - } - /// A parallel version of `visit_all_item_likes`. - pub fn par_visit_all_item_likes<V>(self, visitor: &V) - where - V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, - { - let krate = self.krate(); - par_for_each_in(&krate.owners.raw, |owner| match owner.map(OwnerInfo::node) { - MaybeOwner::Owner(OwnerNode::Item(item)) => visitor.visit_item(item), - MaybeOwner::Owner(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), - MaybeOwner::Owner(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), - MaybeOwner::Owner(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item), - MaybeOwner::Owner(OwnerNode::Crate(_)) - | MaybeOwner::NonOwner(_) - | MaybeOwner::Phantom => {} - }) + for id in krate.trait_items() { + visitor.visit_trait_item(self.trait_item(id)); + } + + for id in krate.impl_items() { + visitor.visit_impl_item(self.impl_item(id)); + } + + for id in krate.foreign_items() { + visitor.visit_foreign_item(self.foreign_item(id)); + } } - /// If you don't care about nesting, you should use the - /// `tcx.hir_module_items()` query or `module_items()` instead. - /// Please see notes in `deep_visit_all_item_likes`. - pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V) + /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to + /// item-likes in a single module. + pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V) where V: Visitor<'hir>, { let module = self.tcx.hir_module_items(module); - for id in module.items.iter() { - visitor.visit_item(self.item(*id)); + for id in module.items() { + visitor.visit_item(self.item(id)); } - for id in module.trait_items.iter() { - visitor.visit_trait_item(self.trait_item(*id)); + for id in module.trait_items() { + visitor.visit_trait_item(self.trait_item(id)); } - for id in module.impl_items.iter() { - visitor.visit_impl_item(self.impl_item(*id)); + for id in module.impl_items() { + visitor.visit_impl_item(self.impl_item(id)); } - for id in module.foreign_items.iter() { - visitor.visit_foreign_item(self.foreign_item(*id)); + for id in module.foreign_items() { + visitor.visit_foreign_item(self.foreign_item(id)); } } @@ -867,6 +830,10 @@ impl<'hir> Map<'hir> { ) } + pub fn expect_owner(self, id: LocalDefId) -> OwnerNode<'hir> { + self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node + } + pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> { match self.tcx.hir_owner(id) { Some(Owner { node: OwnerNode::Item(item), .. }) => item, @@ -914,7 +881,7 @@ impl<'hir> Map<'hir> { #[inline] fn opt_ident(self, id: HirId) -> Option<Ident> { match self.get(id) { - Node::Binding(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), + Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), // A `Ctor` doesn't have an identifier itself, but its parent // struct/variant does. Compare with `hir::Map::opt_span`. Node::Ctor(..) => match self.find(self.get_parent_node(id))? { @@ -947,28 +914,109 @@ impl<'hir> Map<'hir> { } /// Gets the span of the definition of the specified HIR node. - /// This is used by `tcx.get_span` + /// This is used by `tcx.def_span`. pub fn span(self, hir_id: HirId) -> Span { self.opt_span(hir_id) .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id)) } pub fn opt_span(self, hir_id: HirId) -> Option<Span> { + fn until_within(outer: Span, end: Span) -> Span { + if let Some(end) = end.find_ancestor_inside(outer) { + outer.with_hi(end.hi()) + } else { + outer + } + } + + fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) -> Span { + if ident.name != kw::Empty { + let mut span = until_within(item_span, ident.span); + if let Some(g) = generics + && !g.span.is_dummy() + && let Some(g_span) = g.span.find_ancestor_inside(item_span) + { + span = span.to(g_span); + } + span + } else { + item_span + } + } + let span = match self.find(hir_id)? { - Node::Param(param) => param.span, + // Function-like. + Node::Item(Item { kind: ItemKind::Fn(sig, ..), .. }) + | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, ..), .. }) + | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, ..), .. }) => sig.span, + // Constants and Statics. + Node::Item(Item { + kind: + ItemKind::Const(ty, ..) + | ItemKind::Static(ty, ..) + | ItemKind::Impl(Impl { self_ty: ty, .. }), + span: outer_span, + .. + }) + | Node::TraitItem(TraitItem { + kind: TraitItemKind::Const(ty, ..), + span: outer_span, + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Const(ty, ..), + span: outer_span, + .. + }) + | Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Static(ty, ..), + span: outer_span, + .. + }) => until_within(*outer_span, ty.span), + // With generics and bounds. + Node::Item(Item { + kind: ItemKind::Trait(_, _, generics, bounds, _), + span: outer_span, + .. + }) + | Node::TraitItem(TraitItem { + kind: TraitItemKind::Type(bounds, _), + generics, + span: outer_span, + .. + }) => { + let end = if let Some(b) = bounds.last() { b.span() } else { generics.span }; + until_within(*outer_span, end) + } + // Other cases. Node::Item(item) => match &item.kind { - ItemKind::Fn(sig, _, _) => sig.span, - _ => item.span, - }, - Node::ForeignItem(foreign_item) => foreign_item.span, - Node::TraitItem(trait_item) => match &trait_item.kind { - TraitItemKind::Fn(sig, _) => sig.span, - _ => trait_item.span, + ItemKind::Use(path, _) => path.span, + _ => named_span(item.span, item.ident, item.kind.generics()), }, - Node::ImplItem(impl_item) => match &impl_item.kind { - ImplItemKind::Fn(sig, _) => sig.span, - _ => impl_item.span, + Node::Variant(variant) => named_span(variant.span, variant.ident, None), + Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)), + Node::ForeignItem(item) => match item.kind { + ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), + _ => named_span(item.span, item.ident, None), }, + Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)), + Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => { + *fn_decl_span + } + _ => self.span_with_body(hir_id), + }; + Some(span) + } + + /// Like `hir.span()`, but includes the body of items + /// (instead of just the item header) + pub fn span_with_body(self, hir_id: HirId) -> Span { + match self.get(hir_id) { + Node::Param(param) => param.span, + Node::Item(item) => item.span, + Node::ForeignItem(foreign_item) => foreign_item.span, + Node::TraitItem(trait_item) => trait_item.span, + Node::ImplItem(impl_item) => impl_item.span, Node::Variant(variant) => variant.span, Node::Field(field) => field.span, Node::AnonConst(constant) => self.body(constant.body).value.span, @@ -982,33 +1030,15 @@ impl<'hir> Map<'hir> { Node::Ty(ty) => ty.span, Node::TypeBinding(tb) => tb.span, Node::TraitRef(tr) => tr.path.span, - Node::Binding(pat) => pat.span, Node::Pat(pat) => pat.span, Node::Arm(arm) => arm.span, Node::Block(block) => block.span, - Node::Ctor(..) => match self.find(self.get_parent_node(hir_id))? { - Node::Item(item) => item.span, - Node::Variant(variant) => variant.span, - _ => unreachable!(), - }, + Node::Ctor(..) => self.span_with_body(self.get_parent_node(hir_id)), Node::Lifetime(lifetime) => lifetime.span, Node::GenericParam(param) => param.span, Node::Infer(i) => i.span, Node::Local(local) => local.span, Node::Crate(item) => item.spans.inner_span, - }; - Some(span) - } - - /// Like `hir.span()`, but includes the body of function items - /// (instead of just the function header) - pub fn span_with_body(self, hir_id: HirId) -> Span { - match self.find(hir_id) { - Some(Node::TraitItem(item)) => item.span, - Some(Node::ImplItem(impl_item)) => impl_item.span, - Some(Node::Item(item)) => item.span, - Some(_) => self.span(hir_id), - _ => bug!("hir::map::Map::span_with_body: id not in map: {:?}", hir_id), } } @@ -1095,34 +1125,35 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { source_file_names.sort_unstable(); - let mut hcx = tcx.create_stable_hashing_context(); - let mut stable_hasher = StableHasher::new(); - hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); - upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); - source_file_names.hash_stable(&mut hcx, &mut stable_hasher); - if tcx.sess.opts.debugging_opts.incremental_relative_spans { - let definitions = &tcx.definitions_untracked(); - let mut owner_spans: Vec<_> = krate - .owners - .iter_enumerated() - .filter_map(|(def_id, info)| { - let _ = info.as_owner()?; - let def_path_hash = definitions.def_path_hash(def_id); - let span = resolutions.source_span[def_id]; - debug_assert_eq!(span.parent(), None); - Some((def_path_hash, span)) - }) - .collect(); - owner_spans.sort_unstable_by_key(|bn| bn.0); - owner_spans.hash_stable(&mut hcx, &mut stable_hasher); - } - tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); - tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); - // Hash visibility information since it does not appear in HIR. - resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher); - resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher); + let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| { + let mut stable_hasher = StableHasher::new(); + hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); + upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); + source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + if tcx.sess.opts.unstable_opts.incremental_relative_spans { + let definitions = tcx.definitions_untracked(); + let mut owner_spans: Vec<_> = krate + .owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let _ = info.as_owner()?; + let def_path_hash = definitions.def_path_hash(def_id); + let span = resolutions.source_span[def_id]; + debug_assert_eq!(span.parent(), None); + Some((def_path_hash, span)) + }) + .collect(); + owner_spans.sort_unstable_by_key(|bn| bn.0); + owner_spans.hash_stable(&mut hcx, &mut stable_hasher); + } + tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); + tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); + // Hash visibility information since it does not appear in HIR. + resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher); + resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() + }); - let crate_hash: Fingerprint = stable_hasher.finish(); Svh::new(crate_hash.to_smaller_hash()) } @@ -1216,7 +1247,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Some(Node::Ty(_)) => node_str("type"), Some(Node::TypeBinding(_)) => node_str("type binding"), Some(Node::TraitRef(_)) => node_str("trait ref"), - Some(Node::Binding(_)) => node_str("local"), Some(Node::Pat(_)) => node_str("pat"), Some(Node::Param(_)) => node_str("param"), Some(Node::Arm(_)) => node_str("arm"), @@ -1232,85 +1262,48 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { } pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems { - let mut collector = ModuleCollector { - tcx, - submodules: Vec::default(), - items: Vec::default(), - trait_items: Vec::default(), - impl_items: Vec::default(), - foreign_items: Vec::default(), - }; + let mut collector = ItemCollector::new(tcx, false); let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id); collector.visit_mod(hir_mod, span, hir_id); - let ModuleCollector { submodules, items, trait_items, impl_items, foreign_items, .. } = - collector; + let ItemCollector { + submodules, + items, + trait_items, + impl_items, + foreign_items, + body_owners, + .. + } = collector; return ModuleItems { submodules: submodules.into_boxed_slice(), items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), + body_owners: body_owners.into_boxed_slice(), }; - - struct ModuleCollector<'tcx> { - tcx: TyCtxt<'tcx>, - submodules: Vec<LocalDefId>, - items: Vec<ItemId>, - trait_items: Vec<TraitItemId>, - impl_items: Vec<ImplItemId>, - foreign_items: Vec<ForeignItemId>, - } - - impl<'hir> Visitor<'hir> for ModuleCollector<'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - fn visit_item(&mut self, item: &'hir Item<'hir>) { - self.items.push(item.item_id()); - if let ItemKind::Mod(..) = item.kind { - // If this declares another module, do not recurse inside it. - self.submodules.push(item.def_id); - } else { - intravisit::walk_item(self, item) - } - } - - fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { - self.trait_items.push(item.trait_item_id()); - intravisit::walk_trait_item(self, item) - } - - fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { - self.impl_items.push(item.impl_item_id()); - intravisit::walk_impl_item(self, item) - } - - fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { - self.foreign_items.push(item.foreign_item_id()); - intravisit::walk_foreign_item(self, item) - } - } } pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { - let mut collector = CrateCollector { - tcx, - submodules: Vec::default(), - items: Vec::default(), - trait_items: Vec::default(), - impl_items: Vec::default(), - foreign_items: Vec::default(), - }; + let mut collector = ItemCollector::new(tcx, true); + // A "crate collector" and "module collector" start at a + // module item (the former starts at the crate root) but only + // the former needs to collect it. ItemCollector does not do this for us. + collector.submodules.push(CRATE_DEF_ID); tcx.hir().walk_toplevel_module(&mut collector); - let CrateCollector { submodules, items, trait_items, impl_items, foreign_items, .. } = - collector; + let ItemCollector { + submodules, + items, + trait_items, + impl_items, + foreign_items, + body_owners, + .. + } = collector; return ModuleItems { submodules: submodules.into_boxed_slice(), @@ -1318,47 +1311,96 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { trait_items: trait_items.into_boxed_slice(), impl_items: impl_items.into_boxed_slice(), foreign_items: foreign_items.into_boxed_slice(), + body_owners: body_owners.into_boxed_slice(), }; +} - struct CrateCollector<'tcx> { - tcx: TyCtxt<'tcx>, - submodules: Vec<LocalDefId>, - items: Vec<ItemId>, - trait_items: Vec<TraitItemId>, - impl_items: Vec<ImplItemId>, - foreign_items: Vec<ForeignItemId>, +struct ItemCollector<'tcx> { + // When true, it collects all items in the create, + // otherwise it collects items in some module. + crate_collector: bool, + tcx: TyCtxt<'tcx>, + submodules: Vec<LocalDefId>, + items: Vec<ItemId>, + trait_items: Vec<TraitItemId>, + impl_items: Vec<ImplItemId>, + foreign_items: Vec<ForeignItemId>, + body_owners: Vec<LocalDefId>, +} + +impl<'tcx> ItemCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> { + ItemCollector { + crate_collector, + tcx, + submodules: Vec::default(), + items: Vec::default(), + trait_items: Vec::default(), + impl_items: Vec::default(), + foreign_items: Vec::default(), + body_owners: Vec::default(), + } } +} + +impl<'hir> Visitor<'hir> for ItemCollector<'hir> { + type NestedFilter = nested_filter::All; - impl<'hir> Visitor<'hir> for CrateCollector<'hir> { - type NestedFilter = nested_filter::All; + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() + fn visit_item(&mut self, item: &'hir Item<'hir>) { + if associated_body(Node::Item(item)).is_some() { + self.body_owners.push(item.def_id); } - fn visit_item(&mut self, item: &'hir Item<'hir>) { - self.items.push(item.item_id()); + self.items.push(item.item_id()); + + // Items that are modules are handled here instead of in visit_mod. + if let ItemKind::Mod(module) = &item.kind { + self.submodules.push(item.def_id); + // A module collector does not recurse inside nested modules. + if self.crate_collector { + intravisit::walk_mod(self, module, item.hir_id()); + } + } else { intravisit::walk_item(self, item) } + } - fn visit_mod(&mut self, m: &'hir Mod<'hir>, _s: Span, n: HirId) { - self.submodules.push(n.owner); - intravisit::walk_mod(self, m, n); - } + fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { + self.foreign_items.push(item.foreign_item_id()); + intravisit::walk_foreign_item(self, item) + } - fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { - self.foreign_items.push(item.foreign_item_id()); - intravisit::walk_foreign_item(self, item) + fn visit_anon_const(&mut self, c: &'hir AnonConst) { + self.body_owners.push(self.tcx.hir().local_def_id(c.hir_id)); + intravisit::walk_anon_const(self, c) + } + + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { + if matches!(ex.kind, ExprKind::Closure { .. }) { + self.body_owners.push(self.tcx.hir().local_def_id(ex.hir_id)); } + intravisit::walk_expr(self, ex) + } - fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { - self.trait_items.push(item.trait_item_id()); - intravisit::walk_trait_item(self, item) + fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { + if associated_body(Node::TraitItem(item)).is_some() { + self.body_owners.push(item.def_id); } - fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { - self.impl_items.push(item.impl_item_id()); - intravisit::walk_impl_item(self, item) + self.trait_items.push(item.trait_item_id()); + intravisit::walk_trait_item(self, item) + } + + fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { + if associated_body(Node::ImplItem(item)).is_some() { + self.body_owners.push(item.def_id); } + + self.impl_items.push(item.impl_item_id()); + intravisit::walk_impl_item(self, item) } } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 09b142e0c415d..a605e234be95f 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -10,6 +10,7 @@ use crate::ty::query::Providers; use crate::ty::{DefIdTree, ImplSubject, TyCtxt}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; @@ -43,6 +44,7 @@ pub struct ModuleItems { trait_items: Box<[TraitItemId]>, impl_items: Box<[ImplItemId]>, foreign_items: Box<[ForeignItemId]>, + body_owners: Box<[LocalDefId]>, } impl ModuleItems { @@ -61,6 +63,31 @@ impl ModuleItems { pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> + '_ { self.foreign_items.iter().copied() } + + pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ { + self.items + .iter() + .map(|id| id.def_id) + .chain(self.trait_items.iter().map(|id| id.def_id)) + .chain(self.impl_items.iter().map(|id| id.def_id)) + .chain(self.foreign_items.iter().map(|id| id.def_id)) + } + + pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) { + par_for_each_in(&self.items[..], |&id| f(id)) + } + + pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + Send + Sync) { + par_for_each_in(&self.trait_items[..], |&id| f(id)) + } + + pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + Send + Sync) { + par_for_each_in(&self.impl_items[..], |&id| f(id)) + } + + pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + Send + Sync) { + par_for_each_in(&self.foreign_items[..], |&id| f(id)) + } } impl<'tcx> TyCtxt<'tcx> { @@ -85,7 +112,6 @@ pub fn provide(providers: &mut Providers) { let hir = tcx.hir(); hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)) }; - providers.hir_crate = |tcx, ()| tcx.untracked_crate; providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs index d56e87bbb4745..6896837aa9109 100644 --- a/compiler/rustc_middle/src/hir/nested_filter.rs +++ b/compiler/rustc_middle/src/hir/nested_filter.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter; /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`. /// /// **This is the most common choice.** A very common pattern is -/// to use `deep_visit_all_item_likes()` as an outer loop, +/// to use `visit_all_item_likes_in_crate()` as an outer loop, /// and to have the visitor that visits the contents of each item /// using this setting. pub struct OnlyBodies(()); diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 00db19019c480..83d3b0100b844 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -4,18 +4,8 @@ use crate::ty::Ty; use rustc_hir::HirId; use rustc_target::abi::VariantIdx; -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - TyEncodable, - TyDecodable, - TypeFoldable, - HashStable -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum PlaceBase { /// A temporary variable. Rvalue, @@ -27,18 +17,8 @@ pub enum PlaceBase { Upvar(ty::UpvarId), } -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - TyEncodable, - TyDecodable, - TypeFoldable, - HashStable -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box<T>` of the given type. Deref, @@ -58,18 +38,8 @@ pub enum ProjectionKind { Subslice, } -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - TyEncodable, - TyDecodable, - TypeFoldable, - HashStable -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct Projection<'tcx> { /// Type after the projection is applied. pub ty: Ty<'tcx>, @@ -81,7 +51,8 @@ pub struct Projection<'tcx> { /// A `Place` represents how a value is located in memory. /// /// This is an HIR version of [`rustc_middle::mir::Place`]. -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct Place<'tcx> { /// The type of the `PlaceBase` pub base_ty: Ty<'tcx>, @@ -94,7 +65,8 @@ pub struct Place<'tcx> { /// A `PlaceWithHirId` represents how a value is located in memory. /// /// This is an HIR version of [`rustc_middle::mir::Place`]. -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 79f94802d2017..c6fe3e721032f 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -34,7 +34,7 @@ use std::ops::Index; /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct Canonical<'tcx, V> { pub max_universe: ty::UniverseIndex, pub variables: CanonicalVarInfos<'tcx>, @@ -53,7 +53,7 @@ pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>; /// variables. You will need to supply it later to instantiate the /// canonicalized query response. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalVarValues<'tcx> { pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>, } @@ -173,7 +173,7 @@ pub enum CanonicalTyVarKind { /// After we execute a query with a canonicalized key, we get back a /// `Canonical<QueryResponse<..>>`. You can use /// `instantiate_query_result` to access the data in this result. -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] +#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>, @@ -187,7 +187,7 @@ pub struct QueryResponse<'tcx, R> { pub value: R, } -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] +#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec<QueryOutlivesConstraint<'tcx>>, pub member_constraints: Vec<MemberConstraint<'tcx>>, @@ -293,7 +293,7 @@ impl<'tcx, V> Canonical<'tcx, V> { pub type QueryOutlivesConstraint<'tcx> = ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { for <'tcx> { crate::infer::canonical::Certainty, crate::infer::canonical::CanonicalVarInfo<'tcx>, @@ -301,7 +301,7 @@ TrivialTypeFoldableAndLiftImpls! { } } -TrivialTypeFoldableImpls! { +TrivialTypeTraversalImpls! { for <'tcx> { crate::infer::canonical::CanonicalVarInfos<'tcx>, } diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 2350a6ab15546..55e00c4c0d8ef 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -13,7 +13,7 @@ use rustc_span::Span; /// ```text /// R0 member of [O1..On] /// ``` -#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)] +#[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct MemberConstraint<'tcx> { /// The `DefId` of the opaque type causing this constraint: used for error reporting. pub opaque_type_def_id: DefId, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 46c34247d4027..45c6468bc24e5 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -40,7 +40,7 @@ #![feature(extern_types)] #![feature(new_uninit)] #![feature(once_cell)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(min_specialization)] #![feature(trusted_len)] @@ -59,6 +59,7 @@ #![feature(drain_filter)] #![feature(intra_doc_pointers)] #![feature(yeet_expr)] +#![feature(const_option)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 215d8decf2a88..2f45222de4728 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -2,9 +2,7 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{ - Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan}; use rustc_hir::HirId; use rustc_index::vec::IndexVec; use rustc_query_system::ich::StableHashingContext; @@ -227,28 +225,6 @@ impl LintExpectation { } } -pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>); - -impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { - /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. - pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, G> { - self.0.set_primary_message(msg); - self.0.set_is_lint(); - self.0 - } - - /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`. - pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> { - LintDiagnosticBuilder(err) - } -} - -impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> { - pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> { - LintDiagnosticBuilder(self.0.forget_guarantee()) - } -} - pub fn explain_lint_level_source( lint: &'static Lint, level: Level, @@ -324,7 +300,7 @@ pub fn struct_lint_level<'s, 'd>( let has_future_breakage = future_incompatible.map_or( // Default allow lints trigger too often for testing. - sess.opts.debugging_opts.future_incompat_test && lint.default_level != Level::Allow, + sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, |incompat| { matches!(incompat.reason, FutureIncompatibilityReason::FutureReleaseErrorReportNow) }, diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 33b4dff977eb0..0e85c60a36302 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -18,7 +18,7 @@ macro_rules! span_bug { } /////////////////////////////////////////////////////////////////////////// -// Lift and TypeFoldable macros +// Lift and TypeFoldable/TypeVisitable macros // // When possible, use one of these (relatively) convenient macros to write // the impls for you. @@ -48,7 +48,7 @@ macro_rules! CloneLiftImpls { /// Used for types that are `Copy` and which **do not care arena /// allocated data** (i.e., don't need to be folded). #[macro_export] -macro_rules! TrivialTypeFoldableImpls { +macro_rules! TrivialTypeTraversalImpls { (for <$tcx:lifetime> { $($ty:ty,)+ }) => { $( impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty { @@ -58,8 +58,10 @@ macro_rules! TrivialTypeFoldableImpls { ) -> ::std::result::Result<$ty, F::Error> { Ok(self) } + } - fn visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>( + impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty { + fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>( &self, _: &mut F) -> ::std::ops::ControlFlow<F::BreakTy> @@ -71,7 +73,7 @@ macro_rules! TrivialTypeFoldableImpls { }; ($($ty:ty,)+) => { - TrivialTypeFoldableImpls! { + TrivialTypeTraversalImpls! { for <'tcx> { $($ty,)+ } @@ -80,15 +82,15 @@ macro_rules! TrivialTypeFoldableImpls { } #[macro_export] -macro_rules! TrivialTypeFoldableAndLiftImpls { +macro_rules! TrivialTypeTraversalAndLiftImpls { ($($t:tt)*) => { - TrivialTypeFoldableImpls! { $($t)* } + TrivialTypeTraversalImpls! { $($t)* } CloneLiftImpls! { $($t)* } } } #[macro_export] -macro_rules! EnumTypeFoldableImpl { +macro_rules! EnumTypeTraversalImpl { (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { $($variants:tt)* } $(where $($wc:tt)*)*) => { @@ -99,14 +101,22 @@ macro_rules! EnumTypeFoldableImpl { self, folder: &mut V, ) -> ::std::result::Result<Self, V::Error> { - EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output()) + EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output()) } + } + }; - fn visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>( + (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path { + $($variants:tt)* + } $(where $($wc:tt)*)*) => { + impl<$($p),*> $crate::ty::visit::TypeVisitable<$tcx> for $s + $(where $($wc)*)* + { + fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>( &self, visitor: &mut V, ) -> ::std::ops::ControlFlow<V::BreakTy> { - EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) + EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) } } }; @@ -120,7 +130,7 @@ macro_rules! EnumTypeFoldableImpl { (@FoldVariants($this:expr, $folder:expr) input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( + EnumTypeTraversalImpl!( @FoldVariants($this, $folder) input($($input)*) output( @@ -137,7 +147,7 @@ macro_rules! EnumTypeFoldableImpl { (@FoldVariants($this:expr, $folder:expr) input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( + EnumTypeTraversalImpl!( @FoldVariants($this, $folder) input($($input)*) output( @@ -155,7 +165,7 @@ macro_rules! EnumTypeFoldableImpl { (@FoldVariants($this:expr, $folder:expr) input( ($variant:path), $($input:tt)*) output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( + EnumTypeTraversalImpl!( @FoldVariants($this, $folder) input($($input)*) output( @@ -174,12 +184,12 @@ macro_rules! EnumTypeFoldableImpl { (@VisitVariants($this:expr, $visitor:expr) input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( + EnumTypeTraversalImpl!( @VisitVariants($this, $visitor) input($($input)*) output( $variant ( $($variant_arg),* ) => { - $($crate::ty::fold::TypeFoldable::visit_with( + $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* ::std::ops::ControlFlow::CONTINUE @@ -192,12 +202,12 @@ macro_rules! EnumTypeFoldableImpl { (@VisitVariants($this:expr, $visitor:expr) input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( + EnumTypeTraversalImpl!( @VisitVariants($this, $visitor) input($($input)*) output( $variant { $($variant_arg),* } => { - $($crate::ty::fold::TypeFoldable::visit_with( + $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* ::std::ops::ControlFlow::CONTINUE @@ -210,7 +220,7 @@ macro_rules! EnumTypeFoldableImpl { (@VisitVariants($this:expr, $visitor:expr) input( ($variant:path), $($input:tt)*) output( $($output:tt)*) ) => { - EnumTypeFoldableImpl!( + EnumTypeTraversalImpl!( @VisitVariants($this, $visitor) input($($input)*) output( diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 20dcb670cd60b..acced0492efe9 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -25,7 +25,7 @@ pub fn provide(providers: &mut ty::query::Providers) { tcx.hir().krate_attrs(), tcx.sess, sym::move_size_limit, - tcx.sess.opts.debugging_opts.move_size_limit.unwrap_or(0), + tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0), ), type_length_limit: get_limit( tcx.hir().krate_attrs(), diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index d23707a9d316e..96e068a36012a 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -150,7 +150,7 @@ pub fn deprecation_suggestion( span: Span, ) { if let Some(suggestion) = suggestion { - diag.span_suggestion( + diag.span_suggestion_verbose( span, &format!("replace the use of the deprecated {}", kind), suggestion, @@ -443,7 +443,7 @@ impl<'tcx> TyCtxt<'tcx> { // compiling a compiler crate), then let this missing feature // annotation slide. if feature == sym::rustc_private && issue == NonZeroU32::new(27812) { - if self.sess.opts.debugging_opts.force_unstable_if_unmarked { + if self.sess.opts.unstable_opts.force_unstable_if_unmarked { return EvalResult::Allow; } } @@ -471,13 +471,15 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This function will also check if the item is deprecated. /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. + /// + /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature. pub fn check_stability( self, def_id: DefId, id: Option<HirId>, span: Span, method_span: Option<Span>, - ) { + ) -> bool { self.check_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No) } @@ -490,6 +492,8 @@ impl<'tcx> TyCtxt<'tcx> { /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. /// /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally. + /// + /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature. pub fn check_stability_allow_unstable( self, def_id: DefId, @@ -497,7 +501,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Span, method_span: Option<Span>, allow_unstable: AllowUnstable, - ) { + ) -> bool { self.check_optional_stability( def_id, id, @@ -516,6 +520,8 @@ impl<'tcx> TyCtxt<'tcx> { /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary /// for default generic parameters, which only have stability attributes if they were /// added after the type on which they're defined. + /// + /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature. pub fn check_optional_stability( self, def_id: DefId, @@ -524,13 +530,16 @@ impl<'tcx> TyCtxt<'tcx> { method_span: Option<Span>, allow_unstable: AllowUnstable, unmarked: impl FnOnce(Span, DefId), - ) { + ) -> bool { let soft_handler = |lint, span, msg: &_| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { lint.build(msg).emit(); }) }; - match self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable) { + let eval_result = + self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable); + let is_allowed = matches!(eval_result, EvalResult::Allow); + match eval_result { EvalResult::Allow => {} EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable( self.sess, @@ -544,6 +553,8 @@ impl<'tcx> TyCtxt<'tcx> { ), EvalResult::Unmarked => unmarked(span, def_id), } + + is_allowed } pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> { diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs new file mode 100644 index 0000000000000..78080fcd581f6 --- /dev/null +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -0,0 +1,147 @@ +use crate::mir::graph_cyclic_cache::GraphIsCyclicCache; +use crate::mir::predecessors::{PredecessorCache, Predecessors}; +use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources}; +use crate::mir::traversal::PostorderCache; +use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK}; + +use rustc_data_structures::graph; +use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use rustc_index::vec::IndexVec; + +#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] +pub struct BasicBlocks<'tcx> { + basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, + predecessor_cache: PredecessorCache, + switch_source_cache: SwitchSourceCache, + is_cyclic: GraphIsCyclicCache, + postorder_cache: PostorderCache, +} + +impl<'tcx> BasicBlocks<'tcx> { + #[inline] + pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { + BasicBlocks { + basic_blocks, + predecessor_cache: PredecessorCache::new(), + switch_source_cache: SwitchSourceCache::new(), + is_cyclic: GraphIsCyclicCache::new(), + postorder_cache: PostorderCache::new(), + } + } + + /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`. + #[inline] + pub fn is_cfg_cyclic(&self) -> bool { + self.is_cyclic.is_cyclic(self) + } + + #[inline] + pub fn dominators(&self) -> Dominators<BasicBlock> { + dominators(&self) + } + + /// Returns predecessors for each basic block. + #[inline] + pub fn predecessors(&self) -> &Predecessors { + self.predecessor_cache.compute(&self.basic_blocks) + } + + /// Returns basic blocks in a postorder. + #[inline] + pub fn postorder(&self) -> &[BasicBlock] { + self.postorder_cache.compute(&self.basic_blocks) + } + + /// `switch_sources()[&(target, switch)]` returns a list of switch + /// values that lead to a `target` block from a `switch` block. + #[inline] + pub fn switch_sources(&self) -> &SwitchSources { + self.switch_source_cache.compute(&self.basic_blocks) + } + + /// Returns mutable reference to basic blocks. Invalidates CFG cache. + #[inline] + pub fn as_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { + self.invalidate_cfg_cache(); + &mut self.basic_blocks + } + + /// Get mutable access to basic blocks without invalidating the CFG cache. + /// + /// By calling this method instead of e.g. [`BasicBlocks::as_mut`] you promise not to change + /// the CFG. This means that + /// + /// 1) The number of basic blocks remains unchanged + /// 2) The set of successors of each terminator remains unchanged. + /// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator + /// kind is not changed. + /// + /// If any of these conditions cannot be upheld, you should call [`BasicBlocks::invalidate_cfg_cache`]. + #[inline] + pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { + &mut self.basic_blocks + } + + /// Invalidates cached information about the CFG. + /// + /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`]. + /// All other methods that allow you to mutate the basic blocks also call this method + /// themselves, thereby avoiding any risk of accidentaly cache invalidation. + pub fn invalidate_cfg_cache(&mut self) { + self.predecessor_cache.invalidate(); + self.switch_source_cache.invalidate(); + self.is_cyclic.invalidate(); + self.postorder_cache.invalidate(); + } +} + +impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> { + type Target = IndexVec<BasicBlock, BasicBlockData<'tcx>>; + + #[inline] + fn deref(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> { + &self.basic_blocks + } +} + +impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> { + type Node = BasicBlock; +} + +impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> { + #[inline] + fn num_nodes(&self) -> usize { + self.basic_blocks.len() + } +} + +impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> { + #[inline] + fn start_node(&self) -> Self::Node { + START_BLOCK + } +} + +impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> { + #[inline] + fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter { + self.basic_blocks[node].terminator().successors() + } +} + +impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> { + type Item = BasicBlock; + type Iter = Successors<'b>; +} + +impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> { + type Item = BasicBlock; + type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>; +} + +impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { + #[inline] + fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { + self.predecessors()[node].iter().copied() + } +} diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 2336d460407e1..efa9464529e71 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -100,7 +100,7 @@ impl From<InjectedExpressionId> for ExpressionOperandId { } } -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum CoverageKind { Counter { function_source_hash: u64, @@ -148,18 +148,8 @@ impl Debug for CoverageKind { } } -#[derive( - Clone, - TyEncodable, - TyDecodable, - Hash, - HashStable, - TypeFoldable, - PartialEq, - Eq, - PartialOrd, - Ord -)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)] +#[derive(TypeFoldable, TypeVisitable)] pub struct CodeRegion { pub file_name: Symbol, pub start_line: u32, @@ -178,7 +168,8 @@ impl Debug for CodeRegion { } } -#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] +#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum Op { Subtract, Add, diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index a4d78911b2760..f3621cd99d344 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -8,7 +8,7 @@ pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Grap let def_id = body.source.def_id(); let def_name = graphviz_safe_def_name(def_id); let graph_name = format!("Mir_{}", def_name); - let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode; // Nodes let nodes: Vec<Node> = body diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs index c907680bda14a..11ac45943ac58 100644 --- a/compiler/rustc_middle/src/mir/generic_graphviz.rs +++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs @@ -56,11 +56,11 @@ impl< writeln!(w, "{} {}{} {{", kind, cluster, self.graphviz_name)?; // Global graph properties - let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); + let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font); let mut graph_attrs = vec![&font[..]]; let mut content_attrs = vec![&font[..]]; - let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode; if dark_mode { graph_attrs.push(r#"bgcolor="black""#); graph_attrs.push(r#"fontcolor="white""#); diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs index 1279f5aee3691..f97bf2883b369 100644 --- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs +++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs @@ -58,6 +58,6 @@ impl<CTX> HashStable<CTX> for GraphIsCyclicCache { } } -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { GraphIsCyclicCache, } diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index 92c7a358c0a41..5de56dad07a41 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -57,11 +57,11 @@ where W: Write, { // Global graph properties - let font = format!(r#"fontname="{}""#, tcx.sess.opts.debugging_opts.graphviz_font); + let font = format!(r#"fontname="{}""#, tcx.sess.opts.unstable_opts.graphviz_font); let mut graph_attrs = vec![&font[..]]; let mut content_attrs = vec![&font[..]]; - let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode; + let dark_mode = tcx.sess.opts.unstable_opts.graphviz_dark_mode; if dark_mode { graph_attrs.push(r#"bgcolor="black""#); graph_attrs.push(r#"fontcolor="white""#); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 10c4ea63a68b2..eed52ca3eeaa6 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -160,12 +160,18 @@ impl AllocError { } /// The information that makes up a memory access: offset and size. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct AllocRange { pub start: Size, pub size: Size, } +impl fmt::Debug for AllocRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes()) + } +} + /// Free-starting constructor for less syntactic overhead. #[inline(always)] pub fn alloc_range(start: Size, size: Size) -> AllocRange { @@ -173,6 +179,11 @@ pub fn alloc_range(start: Size, size: Size) -> AllocRange { } impl AllocRange { + #[inline] + pub fn from(r: Range<Size>) -> Self { + alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked) + } + #[inline(always)] pub fn end(self) -> Size { self.start + self.size // This does overflow checking. @@ -214,6 +225,8 @@ impl<Tag> Allocation<Tag> { /// Try to create an Allocation of `size` bytes, failing if there is not enough memory /// available to the compiler to do so. + /// + /// If `panic_on_fail` is true, this will never return `Err`. pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> { let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| { // This results in an error that can happen non-deterministically, since the memory @@ -537,21 +550,26 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> { /// Relocations. impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// Returns all relocations overlapping with the given pointer-offset pair. - pub fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] { + fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); self.relocations.range(Size::from_bytes(start)..range.end()) } + /// Returns whether this allocation has relocations overlapping with the given range. + /// + /// Note: this function exists to allow `get_relocations` to be private, in order to somewhat + /// limit access to relocations outside of the `Allocation` abstraction. + /// + pub fn has_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool { + !self.get_relocations(cx, range).is_empty() + } + /// Checks that there are no relocations overlapping with the given range. #[inline(always)] fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { - if self.get_relocations(cx, range).is_empty() { - Ok(()) - } else { - Err(AllocError::ReadPointerAsBytes) - } + if self.has_relocations(cx, range) { Err(AllocError::ReadPointerAsBytes) } else { Ok(()) } } /// Removes all relocations inside the given range. @@ -1084,9 +1102,9 @@ impl InitMask { /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte /// indexes for the first contiguous span of the uninitialized access. #[inline] - pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> { + pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), AllocRange> { if end > self.len { - return Err(self.len..end); + return Err(AllocRange::from(self.len..end)); } let uninit_start = self.find_bit(start, end, false); @@ -1094,7 +1112,7 @@ impl InitMask { match uninit_start { Some(uninit_start) => { let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end); - Err(uninit_start..uninit_end) + Err(AllocRange::from(uninit_start..uninit_end)) } None => Ok(()), } @@ -1165,19 +1183,17 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte /// indexes of the first contiguous uninitialized access. - fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> { + fn is_init(&self, range: AllocRange) -> Result<(), AllocRange> { self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition } /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// error which will report the first range of bytes which is uninitialized. fn check_init(&self, range: AllocRange) -> AllocResult { - self.is_init(range).map_err(|idx_range| { + self.is_init(range).map_err(|uninit_range| { AllocError::InvalidUninitBytes(Some(UninitBytesAccess { - access_offset: range.start, - access_size: range.size, - uninit_offset: idx_range.start, - uninit_size: idx_range.end - idx_range.start, // `Size` subtraction + access: range, + uninit: uninit_range, })) }) } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 65de64c632895..795f23edb3186 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, ConstAlloc, Pointer, Scalar}; +use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; @@ -29,7 +29,7 @@ impl From<ErrorGuaranteed> for ErrorHandled { } } -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { ErrorHandled, } @@ -162,9 +162,9 @@ impl fmt::Display for InvalidProgramInfo<'_> { AlreadyReported(ErrorGuaranteed { .. }) => { write!(f, "encountered constants with type errors, stopping evaluation") } - Layout(ref err) => write!(f, "{}", err), - FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err), - SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty), + Layout(ref err) => write!(f, "{err}"), + FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"), + SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"), } } } @@ -186,7 +186,7 @@ pub enum CheckInAllocMsg { impl fmt::Display for CheckInAllocMsg { /// When this is printed as an error the context looks like this: - /// "{msg}0x01 is not a valid pointer". + /// "{msg}{pointer} is a dangling pointer". fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -194,9 +194,9 @@ impl fmt::Display for CheckInAllocMsg { match *self { CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ", CheckInAllocMsg::MemoryAccessTest => "memory access failed: ", - CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ", + CheckInAllocMsg::PointerArithmeticTest => "out-of-bounds pointer arithmetic: ", CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ", - CheckInAllocMsg::InboundsTest => "", + CheckInAllocMsg::InboundsTest => "out-of-bounds pointer use: ", } ) } @@ -205,14 +205,10 @@ impl fmt::Display for CheckInAllocMsg { /// Details of an access to uninitialized bytes where it is not allowed. #[derive(Debug)] pub struct UninitBytesAccess { - /// Location of the original memory access. - pub access_offset: Size, - /// Size of the original memory access. - pub access_size: Size, - /// Location of the first uninitialized byte that was accessed. - pub uninit_offset: Size, - /// Number of consecutive uninitialized bytes that were accessed. - pub uninit_size: Size, + /// Range of the original memory access. + pub access: AllocRange, + /// Range of the uninit memory that was encountered. (Might not be maximal.) + pub uninit: AllocRange, } /// Information about a size mismatch. @@ -308,98 +304,85 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { - Ub(msg) => write!(f, "{}", msg), + Ub(msg) => write!(f, "{msg}"), Unreachable => write!(f, "entering unreachable code"), BoundsCheckFailed { ref len, ref index } => { - write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index) + write!(f, "indexing out of bounds: the len is {len} but the index is {index}") } DivisionByZero => write!(f, "dividing by zero"), RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"), RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), - InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), + InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"), InvalidVtableDropFn(sig) => write!( f, - "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type", - sig + "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type", ), InvalidVtableSize => { write!(f, "invalid vtable: size is bigger than largest supported object") } - InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg), + InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"), UnterminatedCString(p) => write!( f, - "reading a null-terminated string starting at {:?} with no null found before end of allocation", - p, + "reading a null-terminated string starting at {p:?} with no null found before end of allocation", ), PointerUseAfterFree(a) => { - write!(f, "pointer to {} was dereferenced after this allocation got freed", a) + write!(f, "pointer to {a:?} was dereferenced after this allocation got freed") } PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => { write!( f, - "{}{alloc_id} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds", - msg, - alloc_id = alloc_id, + "{msg}{alloc_id:?} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds", alloc_size = alloc_size.bytes(), - ptr_offset = ptr_offset, ) } PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!( f, - "{}{alloc_id} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds", - msg, - alloc_id = alloc_id, + "{msg}{alloc_id:?} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds", alloc_size = alloc_size.bytes(), ptr_size = ptr_size.bytes(), ptr_size_p = pluralize!(ptr_size.bytes()), - ptr_offset = ptr_offset, ), - DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => { - write!(f, "null pointer is not a valid pointer for this operation") - } - DanglingIntPointer(0, msg) => { - write!(f, "{}null pointer is not a valid pointer", msg) - } DanglingIntPointer(i, msg) => { - write!(f, "{}0x{:x} is not a valid pointer", msg, i) + write!( + f, + "{msg}{pointer} is a dangling pointer (it has no provenance)", + pointer = Pointer::<Option<AllocId>>::from_addr(*i), + ) } AlignmentCheckFailed { required, has } => write!( f, - "accessing memory with alignment {}, but alignment {} is required", - has.bytes(), - required.bytes() + "accessing memory with alignment {has}, but alignment {required} is required", + has = has.bytes(), + required = required.bytes() ), - WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a), - DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a), - ValidationFailure { path: None, msg } => write!(f, "type validation failed: {}", msg), + WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), + DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), + ValidationFailure { path: None, msg } => { + write!(f, "constructing invalid value: {msg}") + } ValidationFailure { path: Some(path), msg } => { - write!(f, "type validation failed at {}: {}", path, msg) + write!(f, "constructing invalid value at {path}: {msg}") } InvalidBool(b) => { - write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b) + write!(f, "interpreting an invalid 8-bit value as a bool: 0x{b:02x}") } InvalidChar(c) => { - write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c) + write!(f, "interpreting an invalid 32-bit value as a char: 0x{c:08x}") } - InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val), + InvalidTag(val) => write!(f, "enum value has invalid tag: {val:x}"), InvalidFunctionPointer(p) => { - write!(f, "using {:?} as function pointer but it does not point to a function", p) + write!(f, "using {p:?} as function pointer but it does not point to a function") } - InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err), - InvalidUninitBytes(Some((alloc, access))) => write!( + InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), + InvalidUninitBytes(Some((alloc, info))) => write!( f, - "reading {} byte{} of memory starting at {:?}, \ - but {} byte{} {} uninitialized starting at {:?}, \ + "reading memory at {alloc:?}{access:?}, \ + but memory is uninitialized at {uninit:?}, \ and this operation requires initialized memory", - access.access_size.bytes(), - pluralize!(access.access_size.bytes()), - Pointer::new(*alloc, access.access_offset), - access.uninit_size.bytes(), - pluralize!(access.uninit_size.bytes()), - pluralize!("is", access.uninit_size.bytes()), - Pointer::new(*alloc, access.uninit_offset), + access = info.access, + uninit = info.uninit, ), InvalidUninitBytes(None) => write!( f, @@ -408,8 +391,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { DeadLocal => write!(f, "accessing a dead local variable"), ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!( f, - "scalar size mismatch: expected {} bytes but got {} bytes instead", - target_size, data_size + "scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead", ), UninhabitedEnumVariantWritten => { write!(f, "writing discriminant of an uninhabited enum") @@ -443,13 +425,13 @@ impl fmt::Display for UnsupportedOpInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UnsupportedOpInfo::*; match self { - Unsupported(ref msg) => write!(f, "{}", msg), + Unsupported(ref msg) => write!(f, "{msg}"), ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"), PartialPointerOverwrite(ptr) => { - write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr) + write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}") } - ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did), - ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did), + ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"), + ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"), } } } @@ -532,11 +514,11 @@ impl fmt::Display for InterpError<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InterpError::*; match *self { - Unsupported(ref msg) => write!(f, "{}", msg), - InvalidProgram(ref msg) => write!(f, "{}", msg), - UndefinedBehavior(ref msg) => write!(f, "{}", msg), - ResourceExhaustion(ref msg) => write!(f, "{}", msg), - MachineStop(ref msg) => write!(f, "{}", msg), + Unsupported(ref msg) => write!(f, "{msg}"), + InvalidProgram(ref msg) => write!(f, "{msg}"), + UndefinedBehavior(ref msg) => write!(f, "{msg}"), + ResourceExhaustion(ref msg) => write!(f, "{msg}"), + MachineStop(ref msg) => write!(f, "{msg}"), } } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 8733a85ef3fad..698024b23301e 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -190,11 +190,7 @@ impl fmt::Debug for AllocId { } } -impl fmt::Display for AllocId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self, f) - } -} +// No "Display" since AllocIds are not usually user-visible. #[derive(TyDecodable, TyEncodable)] enum AllocDiscriminant { @@ -470,7 +466,7 @@ impl<'tcx> TyCtxt<'tcx> { return alloc_id; } let id = alloc_map.reserve(); - debug!("creating alloc {:?} with id {}", alloc, id); + debug!("creating alloc {alloc:?} with id {id:?}"); alloc_map.alloc_map.insert(id, alloc.clone()); alloc_map.dedup.insert(alloc, id); id @@ -538,7 +534,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.get_global_alloc(id) { Some(alloc) => alloc, - None => bug!("could not find allocation for {}", id), + None => bug!("could not find allocation for {id:?}"), } } @@ -546,7 +542,7 @@ impl<'tcx> TyCtxt<'tcx> { /// call this function twice, even with the same `Allocation` will ICE the compiler. pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) { if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) { - bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); + bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}"); } } diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 26da93b9dcebc..d4cdf45d18661 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -144,7 +144,7 @@ impl Provenance for AllocId { } // Print offset only if it is non-zero. if ptr.offset.bytes() > 0 { - write!(f, "+0x{:x}", ptr.offset.bytes())?; + write!(f, "+{:#x}", ptr.offset.bytes())?; } Ok(()) } @@ -181,7 +181,17 @@ impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.provenance { Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f), - None => write!(f, "0x{:x}", self.offset.bytes()), + None => write!(f, "{:#x}[noalloc]", self.offset.bytes()), + } + } +} + +impl<Tag: Provenance> fmt::Display for Pointer<Option<Tag>> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.provenance.is_none() && self.offset.bytes() == 0 { + write!(f, "null pointer") + } else { + fmt::Debug::fmt(self, f) } } } @@ -226,9 +236,14 @@ impl<Tag> Pointer<Option<Tag>> { } impl<Tag> Pointer<Option<Tag>> { + #[inline(always)] + pub fn from_addr(addr: u64) -> Self { + Pointer { provenance: None, offset: Size::from_bytes(addr) } + } + #[inline(always)] pub fn null() -> Self { - Pointer { provenance: None, offset: Size::ZERO } + Pointer::from_addr(0) } } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4895b53bb2677..786927e2dad70 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,8 +1,8 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; -use crate::ty::fold::TypeFoldable; use crate::ty::subst::InternalSubsts; +use crate::ty::visit::TypeVisitable; use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_span::{Span, DUMMY_SP}; @@ -205,14 +205,8 @@ impl<'tcx> TyCtxtEnsure<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - /// Destructure a type-level constant ADT or array into its variant index and its field values. - /// Panics if the destructuring fails, use `try_destructure_const` for fallible version. - pub fn destructure_const(self, const_: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> { - self.try_destructure_const(const_).unwrap() - } - /// Destructure a mir constant ADT or array into its variant index and its field values. - /// Panics if the destructuring fails, use `try_destructure_const` for fallible version. + /// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version. pub fn destructure_mir_constant( self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index e80918d5e5d03..22bbe29c10555 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -29,11 +29,14 @@ pub struct ConstAlloc<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] pub enum ConstValue<'tcx> { - /// Used only for types with `layout::abi::Scalar` ABI and ZSTs. + /// Used only for types with `layout::abi::Scalar` ABI. /// /// Not using the enum `Value` to encode that this must not be `Uninit`. Scalar(Scalar), + /// Only used for ZSTs. + ZeroSized, + /// Used only for `&[u8]` and `&str` Slice { data: ConstAllocation<'tcx>, start: usize, end: usize }, @@ -55,6 +58,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> { Some(match self { ConstValue::Scalar(s) => ConstValue::Scalar(s), + ConstValue::ZeroSized => ConstValue::ZeroSized, ConstValue::Slice { data, start, end } => { ConstValue::Slice { data: tcx.lift(data)?, start, end } } @@ -69,7 +73,7 @@ impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> { match *self { - ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None, + ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, ConstValue::Scalar(val) => Some(val), } } @@ -111,10 +115,6 @@ impl<'tcx> ConstValue<'tcx> { pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { ConstValue::Scalar(Scalar::from_machine_usize(i, cx)) } - - pub fn zst() -> Self { - Self::Scalar(Scalar::ZST) - } } /// A `Scalar` represents an immediate, primitive value existing outside of a @@ -167,7 +167,7 @@ impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), - Scalar::Int(int) => write!(f, "0x{:x}", int), + Scalar::Int(int) => write!(f, "{:#x}", int), } } } @@ -194,8 +194,6 @@ impl<Tag> From<ScalarInt> for Scalar<Tag> { } impl<Tag> Scalar<Tag> { - pub const ZST: Self = Scalar::Int(ScalarInt::ZST); - #[inline(always)] pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self { Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap()) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3f5b16d5ea5f7..0b5d23be58d85 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2,18 +2,17 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -use crate::mir::coverage::{CodeRegion, CoverageKind}; use crate::mir::interpret::{ AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar, }; use crate::mir::visit::MirVisitable; -use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; +use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use crate::ty::{self, List, Ty, TyCtxt}; -use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; +use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex}; use rustc_data_structures::captures::Captures; use rustc_errors::ErrorGuaranteed; @@ -27,14 +26,12 @@ use rustc_target::abi::{Size, VariantIdx}; use polonius_engine::Atom; pub use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::dominators::{dominators, Dominators}; -use rustc_data_structures::graph::{self, GraphSuccessors}; +use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::asm::InlineAsmRegOrRegClass; use either::Either; @@ -42,14 +39,12 @@ use std::borrow::Cow; use std::convert::TryInto; use std::fmt::{self, Debug, Display, Formatter, Write}; use std::ops::{ControlFlow, Index, IndexMut}; -use std::slice; -use std::{iter, mem, option}; +use std::{iter, mem}; -use self::graph_cyclic_cache::GraphIsCyclicCache; -use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; -use self::switch_sources::{SwitchSourceCache, SwitchSources}; +pub use basic_blocks::BasicBlocks; +mod basic_blocks; pub mod coverage; mod generic_graph; pub mod generic_graphviz; @@ -62,14 +57,16 @@ mod predecessors; pub mod pretty; mod query; pub mod spanview; +mod syntax; +pub use syntax::*; mod switch_sources; pub mod tcx; pub mod terminator; -use crate::mir::traversal::PostorderCache; pub use terminator::*; pub mod traversal; mod type_foldable; +mod type_visitable; pub mod visit; pub use self::generic_graph::graphviz_safe_def_name; @@ -129,77 +126,6 @@ pub trait MirPass<'tcx> { } } -/// The various "big phases" that MIR goes through. -/// -/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the -/// dialects forbid certain variants or values in certain phases. The sections below summarize the -/// changes, but do not document them thoroughly. The full documentation is found in the appropriate -/// documentation for the thing the change is affecting. -/// -/// Warning: ordering of variants is significant. -#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] -#[derive(HashStable)] -pub enum MirPhase { - /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also - /// the MIR that analysis such as borrowck uses. - /// - /// One important thing to remember about the behavior of this section of MIR is that drop terminators - /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each - /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop - /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize - /// when things are initialized and when things are de-initialized. That means any code running on this - /// version of MIR must be sure to produce output that drop elaboration can reason about. See the - /// section on the drop terminatorss for more details. - Built = 0, - // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). - // We used to have this for pre-miri MIR based const eval. - Const = 1, - /// This phase checks the MIR for promotable elements and takes them out of the main MIR body - /// by creating a new MIR body per promoted element. After this phase (and thus the termination - /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` - /// query. - ConstsPromoted = 2, - /// Beginning with this phase, the following variants are disallowed: - /// * [`TerminatorKind::DropAndReplace`](terminator::TerminatorKind::DropAndReplace) - /// * [`TerminatorKind::FalseUnwind`](terminator::TerminatorKind::FalseUnwind) - /// * [`TerminatorKind::FalseEdge`](terminator::TerminatorKind::FalseEdge) - /// * [`StatementKind::FakeRead`] - /// * [`StatementKind::AscribeUserType`] - /// * [`Rvalue::Ref`] with `BorrowKind::Shallow` - /// - /// And the following variant is allowed: - /// * [`StatementKind::Retag`] - /// - /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` - /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands - /// are allowed for non-`Copy` types. - DropsLowered = 3, - /// After this projections may only contain deref projections as the first element. - Derefered = 4, - /// Beginning with this phase, the following variant is disallowed: - /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` - /// - /// And the following variant is allowed: - /// * [`StatementKind::SetDiscriminant`] - Deaggregated = 5, - /// Before this phase, generators are in the "source code" form, featuring `yield` statements - /// and such. With this phase change, they are transformed into a proper state machine. Running - /// optimizations before this change can be potentially dangerous because the source code is to - /// some extent a "lie." In particular, `yield` terminators effectively make the value of all - /// locals visible to the caller. This means that dead store elimination before them, or code - /// motion across them, is not correct in general. This is also exasperated by type checking - /// having pre-computed a list of the types that it thinks are ok to be live across a yield - /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new - /// types across a yield point will lead to ICEs becaues of this. - /// - /// Beginning with this phase, the following variants are disallowed: - /// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield) - /// * [`TerminatorKind::GeneratorDrop`](terminator::TerminatorKind::GeneratorDrop) - /// * [`ProjectionElem::Deref`] of `Box` - GeneratorsLowered = 6, - Optimized = 7, -} - impl MirPhase { /// Gets the index of the current MirPhase within the set of all `MirPhase`s. pub fn phase_index(&self) -> usize { @@ -209,7 +135,7 @@ impl MirPhase { /// Where a specific `mir::Body` comes from. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub struct MirSource<'tcx> { pub instance: InstanceDef<'tcx>, @@ -239,7 +165,7 @@ impl<'tcx> MirSource<'tcx> { } } -#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] +#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct GeneratorInfo<'tcx> { /// The yield type of the function, if it is a generator. pub yield_ty: Option<Ty<'tcx>>, @@ -256,11 +182,11 @@ pub struct GeneratorInfo<'tcx> { } /// The lowered representation of a single function. -#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] +#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct Body<'tcx> { /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`] /// that indexes into this vector. - basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, + pub basic_blocks: BasicBlocks<'tcx>, /// Records how far through the "desugaring and optimization" process this particular /// MIR has traversed. This is particularly useful when inlining, since in that context @@ -328,11 +254,6 @@ pub struct Body<'tcx> { /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this. pub is_polymorphic: bool, - predecessor_cache: PredecessorCache, - switch_source_cache: SwitchSourceCache, - is_cyclic: GraphIsCyclicCache, - postorder_cache: PostorderCache, - pub tainted_by_errors: Option<ErrorGuaranteed>, } @@ -360,7 +281,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, source, - basic_blocks, + basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, generator: generator_kind.map(|generator_kind| { Box::new(GeneratorInfo { @@ -378,10 +299,6 @@ impl<'tcx> Body<'tcx> { span, required_consts: Vec::new(), is_polymorphic: false, - predecessor_cache: PredecessorCache::new(), - switch_source_cache: SwitchSourceCache::new(), - is_cyclic: GraphIsCyclicCache::new(), - postorder_cache: PostorderCache::new(), tainted_by_errors, }; body.is_polymorphic = body.has_param_types_or_consts(); @@ -397,7 +314,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, source: MirSource::item(CRATE_DEF_ID.to_def_id()), - basic_blocks, + basic_blocks: BasicBlocks::new(basic_blocks), source_scopes: IndexVec::new(), generator: None, local_decls: IndexVec::new(), @@ -408,10 +325,6 @@ impl<'tcx> Body<'tcx> { required_consts: Vec::new(), var_debug_info: Vec::new(), is_polymorphic: false, - predecessor_cache: PredecessorCache::new(), - switch_source_cache: SwitchSourceCache::new(), - is_cyclic: GraphIsCyclicCache::new(), - postorder_cache: PostorderCache::new(), tainted_by_errors: None, }; body.is_polymorphic = body.has_param_types_or_consts(); @@ -425,48 +338,7 @@ impl<'tcx> Body<'tcx> { #[inline] pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { - // Because the user could mutate basic block terminators via this reference, we need to - // invalidate the caches. - // - // FIXME: Use a finer-grained API for this, so only transformations that alter terminators - // invalidate the caches. - self.predecessor_cache.invalidate(); - self.switch_source_cache.invalidate(); - self.is_cyclic.invalidate(); - self.postorder_cache.invalidate(); - &mut self.basic_blocks - } - - #[inline] - pub fn basic_blocks_and_local_decls_mut( - &mut self, - ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { - self.predecessor_cache.invalidate(); - self.switch_source_cache.invalidate(); - self.is_cyclic.invalidate(); - self.postorder_cache.invalidate(); - (&mut self.basic_blocks, &mut self.local_decls) - } - - #[inline] - pub fn basic_blocks_local_decls_mut_and_var_debug_info( - &mut self, - ) -> ( - &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, - &mut LocalDecls<'tcx>, - &mut Vec<VarDebugInfo<'tcx>>, - ) { - self.predecessor_cache.invalidate(); - self.switch_source_cache.invalidate(); - self.is_cyclic.invalidate(); - self.postorder_cache.invalidate(); - (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) - } - - /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the - /// `START_BLOCK`. - pub fn is_cfg_cyclic(&self) -> bool { - self.is_cyclic.is_cyclic(self) + self.basic_blocks.as_mut() } #[inline] @@ -540,14 +412,6 @@ impl<'tcx> Body<'tcx> { self.local_decls.drain(self.arg_count + 1..) } - /// Changes a statement to a nop. This is both faster than deleting instructions and avoids - /// invalidating statement indices in `Location`s. - pub fn make_statement_nop(&mut self, location: Location) { - let block = &mut self.basic_blocks[location.block]; - debug_assert!(location.statement_index < block.statements.len()); - block.statements[location.statement_index].make_nop() - } - /// Returns the source info associated with `location`. pub fn source_info(&self, location: Location) -> &SourceInfo { let block = &self[location.block]; @@ -583,23 +447,6 @@ impl<'tcx> Body<'tcx> { .unwrap_or_else(|| Either::Right(block_data.terminator())) } - #[inline] - pub fn predecessors(&self) -> &Predecessors { - self.predecessor_cache.compute(&self.basic_blocks) - } - - /// `body.switch_sources()[&(target, switch)]` returns a list of switch - /// values that lead to a `target` block from a `switch` block. - #[inline] - pub fn switch_sources(&self) -> &SwitchSources { - self.switch_source_cache.compute(&self.basic_blocks) - } - - #[inline] - pub fn dominators(&self) -> Dominators<BasicBlock> { - dominators(self) - } - #[inline] pub fn yield_ty(&self) -> Option<Ty<'tcx>> { self.generator.as_ref().and_then(|generator| generator.yield_ty) @@ -644,11 +491,11 @@ impl<'tcx> Index<BasicBlock> for Body<'tcx> { impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> { #[inline] fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { - &mut self.basic_blocks_mut()[index] + &mut self.basic_blocks.as_mut()[index] } } -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable)] +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub enum ClearCrossCrate<T> { Clear, Set(T), @@ -731,102 +578,6 @@ impl SourceInfo { } } -/////////////////////////////////////////////////////////////////////////// -// Borrow kinds - -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable)] -pub enum BorrowKind { - /// Data must be immutable and is aliasable. - Shared, - - /// The immediately borrowed place must be immutable, but projections from - /// it don't need to be. For example, a shallow borrow of `a.b` doesn't - /// conflict with a mutable borrow of `a.b.c`. - /// - /// This is used when lowering matches: when matching on a place we want to - /// ensure that place have the same value from the start of the match until - /// an arm is selected. This prevents this code from compiling: - /// ```compile_fail,E0510 - /// let mut x = &Some(0); - /// match *x { - /// None => (), - /// Some(_) if { x = &None; false } => (), - /// Some(_) => (), - /// } - /// ``` - /// This can't be a shared borrow because mutably borrowing (*x as Some).0 - /// should not prevent `if let None = x { ... }`, for example, because the - /// mutating `(*x as Some).0` can't affect the discriminant of `x`. - /// We can also report errors with this kind of borrow differently. - Shallow, - - /// Data must be immutable but not aliasable. This kind of borrow - /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when the closure is - /// borrowing or mutating a mutable referent, e.g.: - /// ``` - /// let mut z = 3; - /// let x: &mut isize = &mut z; - /// let y = || *x += 5; - /// ``` - /// If we were to try to translate this closure into a more explicit - /// form, we'd encounter an error with the code as written: - /// ```compile_fail,E0594 - /// struct Env<'a> { x: &'a &'a mut isize } - /// let mut z = 3; - /// let x: &mut isize = &mut z; - /// let y = (&mut Env { x: &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// ``` - /// This is then illegal because you cannot mutate an `&mut` found - /// in an aliasable location. To solve, you'd have to translate with - /// an `&mut` borrow: - /// ```compile_fail,E0596 - /// struct Env<'a> { x: &'a mut &'a mut isize } - /// let mut z = 3; - /// let x: &mut isize = &mut z; - /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } - /// ``` - /// Now the assignment to `**env.x` is legal, but creating a - /// mutable pointer to `x` is not because `x` is not mutable. We - /// could fix this by declaring `x` as `let mut x`. This is ok in - /// user code, if awkward, but extra weird for closures, since the - /// borrow is hidden. - /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. - Unique, - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - /// (i.e., `adjustment::Adjust::Borrow`). - allow_two_phase_borrow: bool, - }, -} - -impl BorrowKind { - pub fn allows_two_phase_borrow(&self) -> bool { - match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, - } - } - - pub fn describe_mutability(&self) -> String { - match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => { - "immutable".to_string() - } - BorrowKind::Mut { .. } => "mutable".to_string(), - } - } -} - /////////////////////////////////////////////////////////////////////////// // Variables and temps @@ -905,7 +656,7 @@ pub enum ImplicitSelfKind { None, } -TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } +TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx>, } mod binding_form_impl { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -950,7 +701,7 @@ pub struct BlockTailInfo { /// /// This can be a binding declared by the user, a temporary inserted by the compiler, a function /// argument, or the return place. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct LocalDecl<'tcx> { /// Whether this is a mutable binding (i.e., `let x` or `let mut x`). /// @@ -1085,7 +836,7 @@ static_assert_size!(LocalDecl<'_>, 56); /// /// Not used for non-StaticRef temporaries, the return place, or anonymous /// function parameters. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum LocalInfo<'tcx> { /// A user-defined local variable or function parameter /// @@ -1174,6 +925,15 @@ impl<'tcx> LocalDecl<'tcx> { } } + /// Returns `true` if this is a DerefTemp + pub fn is_deref_temp(&self) -> bool { + match self.local_info { + Some(box LocalInfo::DerefTemp) => return true, + _ => (), + } + return false; + } + /// Returns `true` is the local is from a compiler desugaring, e.g., /// `__next` from a `for` loop. #[inline] @@ -1224,7 +984,7 @@ impl<'tcx> LocalDecl<'tcx> { } } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum VarDebugInfoContents<'tcx> { /// NOTE(eddyb) There's an unenforced invariant that this `Place` is /// based on a `Local`, not a `Static`, and contains no indexing. @@ -1242,7 +1002,7 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> { } /// Debug information pertaining to a user variable. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct VarDebugInfo<'tcx> { pub name: Symbol, @@ -1295,10 +1055,12 @@ impl BasicBlock { } /////////////////////////////////////////////////////////////////////////// -// BasicBlockData and Terminator +// BasicBlockData +/// Data for a basic block, including a list of its statements. +/// /// See [`BasicBlock`] for documentation on what basic blocks are at a high level. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct BasicBlockData<'tcx> { /// List of statements in this block. pub statements: Vec<Statement<'tcx>>, @@ -1320,53 +1082,6 @@ pub struct BasicBlockData<'tcx> { pub is_cleanup: bool, } -/// Information about an assertion failure. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] -pub enum AssertKind<O> { - BoundsCheck { len: O, index: O }, - Overflow(BinOp, O, O), - OverflowNeg(O), - DivisionByZero(O), - RemainderByZero(O), - ResumedAfterReturn(GeneratorKind), - ResumedAfterPanic(GeneratorKind), -} - -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] -pub enum InlineAsmOperand<'tcx> { - In { - reg: InlineAsmRegOrRegClass, - value: Operand<'tcx>, - }, - Out { - reg: InlineAsmRegOrRegClass, - late: bool, - place: Option<Place<'tcx>>, - }, - InOut { - reg: InlineAsmRegOrRegClass, - late: bool, - in_value: Operand<'tcx>, - out_place: Option<Place<'tcx>>, - }, - Const { - value: Box<Constant<'tcx>>, - }, - SymFn { - value: Box<Constant<'tcx>>, - }, - SymStatic { - def_id: DefId, - }, -} - -/// Type for MIR `Assert` terminator error messages. -pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; - -pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a; -pub type SuccessorsMut<'a> = - iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; - impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { BasicBlockData { statements: vec![], terminator, is_cleanup: false } @@ -1375,7 +1090,7 @@ impl<'tcx> BasicBlockData<'tcx> { /// Accessor for terminator. /// /// Terminator may not be None after construction of the basic block is complete. This accessor - /// provides a convenience way to reach the terminator. + /// provides a convenient way to reach the terminator. #[inline] pub fn terminator(&self) -> &Terminator<'tcx> { self.terminator.as_ref().expect("invalid terminator state") @@ -1582,7 +1297,8 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> { /////////////////////////////////////////////////////////////////////////// // Statements -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +/// A statement in a basic block, including information about its source code. +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Statement<'tcx> { pub source_info: SourceInfo, pub kind: StatementKind<'tcx>, @@ -1609,223 +1325,6 @@ impl Statement<'_> { } } -/// The various kinds of statements that can appear in MIR. -/// -/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which -/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions, -/// causing an ICE if they are violated. -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] -pub enum StatementKind<'tcx> { - /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except - /// without the possibility of dropping the previous value (that must be done separately, if at - /// all). The *exact* way this works is undecided. It probably does something like evaluating - /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various - /// parts of this may do type specific things that are more complicated than simply copying - /// bytes. - /// - /// **Needs clarification**: The implication of the above idea would be that assignment implies - /// that the resulting value is initialized. I believe we could commit to this separately from - /// committing to whatever part of the memory model we would need to decide on to make the above - /// paragragh precise. Do we want to? - /// - /// Assignments in which the types of the place and rvalue differ are not well-formed. - /// - /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for - /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we - /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this - /// interesting for optimizations? Do we want to allow such optimizations? - /// - /// **Needs clarification**: We currently require that the LHS place not overlap with any place - /// read as part of computation of the RHS for some rvalues (generally those not producing - /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion, - /// it is also unclear in what order the components are evaluated. - /// - /// [#68364]: https://github.com/rust-lang/rust/issues/68364 - /// - /// See [`Rvalue`] documentation for details on each of those. - Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), - - /// This represents all the reading that a pattern match may do (e.g., inspecting constants and - /// discriminant values), and the kind of pattern it comes from. This is in order to adapt - /// potential error messages to these specific patterns. - /// - /// Note that this also is emitted for regular `let` bindings to ensure that locals that are - /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` - /// - /// When executed at runtime this is a nop. - /// - /// Disallowed after drop elaboration. - FakeRead(Box<(FakeReadCause, Place<'tcx>)>), - - /// Write the discriminant for a variant to the enum Place. - /// - /// This is permitted for both generators and ADTs. This does not necessarily write to the - /// entire place; instead, it writes to the minimum set of bytes as required by the layout for - /// the type. - SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx }, - - /// Deinitializes the place. - /// - /// This writes `uninit` bytes to the entire place. - Deinit(Box<Place<'tcx>>), - - /// `StorageLive` and `StorageDead` statements mark the live range of a local. - /// - /// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These - /// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead` - /// statements for a particular local, the local is always considered live. - /// - /// More precisely, the MIR validator currently does a `MaybeStorageLiveLocals` analysis to - /// check validity of each use of a local. I believe this is equivalent to requiring for every - /// use of a local, there exist at least one path from the root to that use that contains a - /// `StorageLive` more recently than a `StorageDead`. - /// - /// **Needs clarification**: Is it permitted to have two `StorageLive`s without an intervening - /// `StorageDead`? Two `StorageDead`s without an intervening `StorageLive`? LLVM says poison, - /// yes. If the answer to any of these is "no," is breaking that rule UB or is it an error to - /// have a path in the CFG that might do this? - StorageLive(Local), - - /// See `StorageLive` above. - StorageDead(Local), - - /// Retag references in the given place, ensuring they got fresh tags. - /// - /// This is part of the Stacked Borrows model. These statements are currently only interpreted - /// by miri and only generated when `-Z mir-emit-retag` is passed. See - /// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for - /// more details. - /// - /// For code that is not specific to stacked borrows, you should consider retags to read - /// and modify the place in an opaque way. - Retag(RetagKind, Box<Place<'tcx>>), - - /// Encodes a user's type ascription. These need to be preserved - /// intact so that NLL can respect them. For example: - /// ```ignore (illustrative) - /// let a: T = y; - /// ``` - /// The effect of this annotation is to relate the type `T_y` of the place `y` - /// to the user-given type `T`. The effect depends on the specified variance: - /// - /// - `Covariant` -- requires that `T_y <: T` - /// - `Contravariant` -- requires that `T_y :> T` - /// - `Invariant` -- requires that `T_y == T` - /// - `Bivariant` -- no effect - /// - /// When executed at runtime this is a nop. - /// - /// Disallowed after drop elaboration. - AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), - - /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A - /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage - /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates - /// executable code, to increment a counter variable at runtime, each time the code region is - /// executed. - Coverage(Box<Coverage>), - - /// Denotes a call to the intrinsic function `copy_nonoverlapping`. - /// - /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, - /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and - /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of - /// the `src` place are copied to the continguous range of bytes beginning with the first byte - /// of `dest`. - /// - /// **Needs clarification**: In what order are operands computed and dereferenced? It should - /// probably match the order for assignment, but that is also undecided. - /// - /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? - /// I vaguely remember Ralf saying somewhere that he thought it should not be. - CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>), - - /// No-op. Useful for deleting instructions without affecting statement indices. - Nop, -} - -impl<'tcx> StatementKind<'tcx> { - pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { - match self { - StatementKind::Assign(x) => Some(x), - _ => None, - } - } - - pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> { - match self { - StatementKind::Assign(x) => Some(x), - _ => None, - } - } -} - -/// Describes what kind of retag is to be performed. -#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] -pub enum RetagKind { - /// The initial retag when entering a function. - FnEntry, - /// Retag preparing for a two-phase borrow. - TwoPhase, - /// Retagging raw pointers. - Raw, - /// A "normal" retag. - Default, -} - -/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. -#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] -pub enum FakeReadCause { - /// Inject a fake read of the borrowed input at the end of each guards - /// code. - /// - /// This should ensure that you cannot change the variant for an enum while - /// you are in the midst of matching on it. - ForMatchGuard, - - /// `let x: !; match x {}` doesn't generate any read of x so we need to - /// generate a read of x to check that it is initialized and safe. - /// - /// If a closure pattern matches a Place starting with an Upvar, then we introduce a - /// FakeRead for that Place outside the closure, in such a case this option would be - /// Some(closure_def_id). - /// Otherwise, the value of the optional DefId will be None. - ForMatchedPlace(Option<DefId>), - - /// A fake read of the RefWithinGuard version of a bind-by-value variable - /// in a match guard to ensure that its value hasn't change by the time - /// we create the OutsideGuard version. - ForGuardBinding, - - /// Officially, the semantics of - /// - /// `let pattern = <expr>;` - /// - /// is that `<expr>` is evaluated into a temporary and then this temporary is - /// into the pattern. - /// - /// However, if we see the simple pattern `let var = <expr>`, we optimize this to - /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, - /// but in some cases it can affect the borrow checker, as in #53695. - /// Therefore, we insert a "fake read" here to ensure that we get - /// appropriate errors. - /// - /// If a closure pattern matches a Place starting with an Upvar, then we introduce a - /// FakeRead for that Place outside the closure, in such a case this option would be - /// Some(closure_def_id). - /// Otherwise, the value of the optional DefId will be None. - ForLet(Option<DefId>), - - /// If we have an index expression like - /// - /// (*x)[1][{ x = y; 4}] - /// - /// then the first bounds check is invalidated when we evaluate the second - /// index expression. Thus we create a fake borrow of `x` across the second - /// indexer, which will cause a borrow check error. - ForIndex, -} - impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; @@ -1870,169 +1369,25 @@ impl Debug for Statement<'_> { } } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] -pub struct Coverage { - pub kind: CoverageKind, - pub code_region: Option<CodeRegion>, -} +impl<'tcx> StatementKind<'tcx> { + pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { + match self { + StatementKind::Assign(x) => Some(x), + _ => None, + } + } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] -pub struct CopyNonOverlapping<'tcx> { - pub src: Operand<'tcx>, - pub dst: Operand<'tcx>, - /// Number of elements to copy from src to dest, not bytes. - pub count: Operand<'tcx>, + pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> { + match self { + StatementKind::Assign(x) => Some(x), + _ => None, + } + } } /////////////////////////////////////////////////////////////////////////// // Places -/// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical -/// object as places in Rust. This of course means that what exactly they are is undecided and part -/// of the Rust memory model. However, they will likely contain at least the following pieces of -/// information in some form: -/// -/// 1. The address in memory that the place refers to. -/// 2. The provenance with which the place is being accessed. -/// 3. The type of the place and an optional variant index. See [`PlaceTy`][tcx::PlaceTy]. -/// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. -/// -/// We'll give a description below of how all pieces of the place except for the provenance are -/// calculated. We cannot give a description of the provenance, because that is part of the -/// undecided aliasing model - we only include it here at all to acknowledge its existence. -/// -/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has -/// the address of the local's allocation and the type of the local. -/// -/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation -/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation. -/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under -/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and -/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into -/// the current MIR semantics in a clean way - possibly this needs some design work first. -/// -/// For places that are not locals, ie they have a non-empty list of projections, we define the -/// values as a function of the parent place, that is the place with its last [`ProjectionElem`] -/// stripped. The way this is computed of course depends on the kind of that last projection -/// element: -/// -/// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the -/// given one, and makes no other changes. A `Downcast` projection on a place with its variant -/// index already set is not well-formed. -/// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a -/// place referring to one of the fields of the type. The resulting address is the parent -/// address, plus the offset of the field. The type becomes the type of the field. If the parent -/// was unsized and so had metadata associated with it, then the metadata is retained if the -/// field is unsized and thrown out if it is sized. -/// -/// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or -/// generator has more than one variant, the parent place's variant index must be set, indicating -/// which variant is being used. If it has just one variant, the variant index may or may not be -/// included - the single possible variant is inferred if it is not included. -/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the -/// place as described in the documentation for the `ProjectionElem`. The resulting address is -/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent -/// place has type `[T; N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any -/// resulting metadata is thrown out. -/// - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new -/// address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`. -/// However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the -/// length of the subslice. -/// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`. -/// However, `Index` additionally takes a local from which the value of the index is computed at -/// runtime. Computing the value of the index involves interpreting the `Local` as a -/// `Place { local, projection: [] }`, and then computing its value as if done via -/// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must -/// have type `usize`. -/// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most -/// complicated. They are only legal on parent places that are references, pointers, or `Box`. A -/// `Deref` projection begins by loading a value from the parent place, as if by -/// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the -/// pointee's type. The resulting address is the address that was stored in the pointer. If the -/// pointee type is unsized, the pointer additionally stored the value of the metadata. -/// -/// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not -/// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not -/// point to an actual allocation. -/// -/// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed -/// in [UCG#319]. The options include that every place must obey those rules, that only some places -/// must obey them, or that places impose no rules of their own. -/// -/// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319 -/// -/// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken -/// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)] -pub struct Place<'tcx> { - pub local: Local, - - /// projection out of a place (access a field, deref a pointer, etc) - pub projection: &'tcx List<PlaceElem<'tcx>>, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Place<'_>, 16); - -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] -pub enum ProjectionElem<V, T> { - Deref, - Field(Field, T), - /// Index into a slice/array. - /// - /// Note that this does not also dereference, and so it does not exactly correspond to slice - /// indexing in Rust. In other words, in the below Rust code: - /// - /// ```rust - /// let x = &[1, 2, 3, 4]; - /// let i = 2; - /// x[i]; - /// ``` - /// - /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same - /// thing is true of the `ConstantIndex` and `Subslice` projections below. - Index(V), - - /// These indices are generated by slice patterns. Easiest to explain - /// by example: - /// - /// ```ignore (illustrative) - /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, - /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, - /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, - /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, - /// ``` - ConstantIndex { - /// index or -index (in Python terms), depending on from_end - offset: u64, - /// The thing being indexed must be at least this long. For arrays this - /// is always the exact length. - min_length: u64, - /// Counting backwards from end? This is always false when indexing an - /// array. - from_end: bool, - }, - - /// These indices are generated by slice patterns. - /// - /// If `from_end` is true `slice[from..slice.len() - to]`. - /// Otherwise `array[from..to]`. - Subslice { - from: u64, - to: u64, - /// Whether `to` counts from the start or end of the array/slice. - /// For `PlaceElem`s this is `true` if and only if the base is a slice. - /// For `ProjectionKind`, this can also be `true` for arrays. - from_end: bool, - }, - - /// "Downcast" to a variant of an enum or a generator. - /// - /// The included Symbol is the name of the variant, used for printing MIR. - Downcast(Option<Symbol>, VariantIdx), -} - impl<V, T> ProjectionElem<V, T> { /// Returns `true` if the target of this projection may refer to a different region of memory /// than the base. @@ -2042,6 +1397,7 @@ impl<V, T> ProjectionElem<V, T> { Self::Field(_, _) | Self::Index(_) + | Self::OpaqueCast(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => false, @@ -2059,15 +1415,6 @@ impl<V, T> ProjectionElem<V, T> { } } -/// Alias for projections as they appear in places, where the base is a place -/// and the index is a local. -pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; - -// This type is fairly frequently used, so we shouldn't unintentionally increase -// its size. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PlaceElem<'_>, 24); - /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. pub type ProjectionKind = ProjectionElem<(), ()>; @@ -2228,7 +1575,9 @@ impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { for elem in self.projection.iter().rev() { match elem { - ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { + ProjectionElem::OpaqueCast(_) + | ProjectionElem::Downcast(_, _) + | ProjectionElem::Field(_, _) => { write!(fmt, "(").unwrap(); } ProjectionElem::Deref => { @@ -2244,6 +1593,9 @@ impl Debug for Place<'_> { for elem in self.projection.iter() { match elem { + ProjectionElem::OpaqueCast(ty) => { + write!(fmt, " as {})", ty)?; + } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {})", name)?; } @@ -2318,7 +1670,7 @@ impl SourceScope { } } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct SourceScopeData<'tcx> { pub span: Span, pub parent_scope: Option<SourceScope>, @@ -2349,48 +1701,6 @@ pub struct SourceScopeLocalData { /////////////////////////////////////////////////////////////////////////// // Operands -/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of -/// the memory model. One proposal for a definition of values can be found [on UCG][value-def]. -/// -/// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md -/// -/// The most common way to create values is via loading a place. Loading a place is an operation -/// which reads the memory of the place and converts it to a value. This is a fundamentally *typed* -/// operation. The nature of the value produced depends on the type of the conversion. Furthermore, -/// there may be other effects: if the type has a validity constraint loading the place might be UB -/// if the validity constraint is not met. -/// -/// **Needs clarification:** Ralf proposes that loading a place not have side-effects. -/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this -/// something we can even decide without knowing more about Rust's memory model? -/// -/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri -/// currently implements it, but it seems like this may be something to check against in the -/// validator. -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum Operand<'tcx> { - /// Creates a value by loading the given place. - /// - /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there - /// is no such requirement. - Copy(Place<'tcx>), - - /// Creates a value by performing loading the place, just like the `Copy` operand. - /// - /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide - /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this - /// place without first re-initializing it. - /// - /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 - Move(Place<'tcx>), - - /// Constants are already semantically values, and remain unchanged. - Constant(Box<Constant<'tcx>>), -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Operand<'_>, 24); - impl<'tcx> Debug for Operand<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Operand::*; @@ -2416,7 +1726,7 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::zst(), ty), + literal: ConstantKind::Val(ConstValue::ZeroSized, ty), })) } @@ -2489,138 +1799,6 @@ impl<'tcx> Operand<'tcx> { /////////////////////////////////////////////////////////////////////////// /// Rvalues -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] -/// The various kinds of rvalues that can appear in MIR. -/// -/// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below. -/// -/// Computing any rvalue begins by evaluating the places and operands in some order (**Needs -/// clarification**: Which order?). These are then used to produce a "value" - the same kind of -/// value that an [`Operand`] produces. -pub enum Rvalue<'tcx> { - /// Yields the operand unchanged - Use(Operand<'tcx>), - - /// Creates an array where each element is the value of the operand. - /// - /// This is the cause of a bug in the case where the repetition count is zero because the value - /// is not dropped, see [#74836]. - /// - /// Corresponds to source code like `[x; 32]`. - /// - /// [#74836]: https://github.com/rust-lang/rust/issues/74836 - Repeat(Operand<'tcx>, ty::Const<'tcx>), - - /// Creates a reference of the indicated kind to the place. - /// - /// There is not much to document here, because besides the obvious parts the semantics of this - /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing - /// exactly what the behavior of this operation should be. - /// - /// `Shallow` borrows are disallowed after drop lowering. - Ref(Region<'tcx>, BorrowKind, Place<'tcx>), - - /// Creates a pointer/reference to the given thread local. - /// - /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a - /// `*const T`, and if neither of those apply a `&T`. - /// - /// **Note:** This is a runtime operation that actually executes code and is in this sense more - /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to - /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. - /// - /// **Needs clarification**: Are there weird additional semantics here related to the runtime - /// nature of this operation? - ThreadLocalRef(DefId), - - /// Creates a pointer with the indicated mutability to the place. - /// - /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like - /// `&raw v` or `addr_of!(v)`. - /// - /// Like with references, the semantics of this operation are heavily dependent on the aliasing - /// model. - AddressOf(Mutability, Place<'tcx>), - - /// Yields the length of the place, as a `usize`. - /// - /// If the type of the place is an array, this is the array length. For slices (`[T]`, not - /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is - /// ill-formed for places of other types. - Len(Place<'tcx>), - - /// Performs essentially all of the casts that can be performed via `as`. - /// - /// This allows for casts from/to a variety of types. - /// - /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why - /// `ArrayToPointer` and `MutToConstPointer` are special. - Cast(CastKind, Operand<'tcx>, Ty<'tcx>), - - /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second - /// parameter may be a `usize` as well. - /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, - /// raw pointers, or function pointers and return a `bool`. The types of the operands must be - /// matching, up to the usual caveat of the lifetimes in function pointers. - /// * Left and right shift operations accept signed or unsigned integers not necessarily of the - /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is - /// truncated as needed. - /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching - /// types and return a value of that type. - /// * The remaining operations accept signed integers, unsigned integers, or floats with - /// matching types and return a value of that type. - BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), - - /// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the - /// same computation as the matching `BinaryOp`, checks if the infinite precison result would be - /// unequal to the actual result and sets the `bool` if this is the case. - /// - /// This only supports addition, subtraction, multiplication, and shift operations on integers. - CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), - - /// Computes a value as described by the operation. - NullaryOp(NullOp, Ty<'tcx>), - - /// Exactly like `BinaryOp`, but less operands. - /// - /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; - /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds - /// return a value with the same type as their operand. - UnaryOp(UnOp, Operand<'tcx>), - - /// Computes the discriminant of the place, returning it as an integer of type - /// [`discriminant_ty`]. Returns zero for types without discriminant. - /// - /// The validity requirements for the underlying value are undecided for this rvalue, see - /// [#91095]. Note too that the value of the discriminant is not the same thing as the - /// variant index; use [`discriminant_for_variant`] to convert. - /// - /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty - /// [#91095]: https://github.com/rust-lang/rust/issues/91095 - /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant - Discriminant(Place<'tcx>), - - /// Creates an aggregate value, like a tuple or struct. - /// - /// This is needed because dataflow analysis needs to distinguish - /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` - /// has a destructor. - /// - /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After - /// generator lowering, `Generator` aggregate kinds are disallowed too. - Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), - - /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. - /// - /// This is different from a normal transmute because dataflow analysis will treat the box as - /// initialized but its content as uninitialized. Like other pointer casts, this in general - /// affects alias analysis. - ShallowInitBox(Operand<'tcx>, Ty<'tcx>), -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Rvalue<'_>, 40); - impl<'tcx> Rvalue<'tcx> { /// Returns true if rvalue can be safely removed when the result is unused. #[inline] @@ -2632,6 +1810,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, Rvalue::Use(_) + | Rvalue::CopyForDeref(_) | Rvalue::Repeat(_, _) | Rvalue::Ref(_, _, _) | Rvalue::ThreadLocalRef(_) @@ -2653,88 +1832,20 @@ impl<'tcx> Rvalue<'tcx> { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum CastKind { - /// An exposing pointer to address cast. A cast between a pointer and an integer type, or - /// between a function pointer and an integer type. - /// See the docs on `expose_addr` for more details. - PointerExposeAddress, - /// An address-to-pointer cast that picks up an exposed provenance. - /// See the docs on `from_exposed_addr` for more details. - PointerFromExposedAddress, - /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are - /// translated into `&raw mut/const *r`, i.e., they are not actually casts. - Pointer(PointerCast), - /// Remaining unclassified casts. - Misc, -} - -#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum AggregateKind<'tcx> { - /// The type is of the element - Array(Ty<'tcx>), - Tuple, - - /// The second field is the variant index. It's equal to 0 for struct - /// and union expressions. The fourth field is - /// 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` - Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), - - Closure(DefId, SubstsRef<'tcx>), - Generator(DefId, SubstsRef<'tcx>, hir::Movability), -} +impl BorrowKind { + pub fn allows_two_phase_borrow(&self) -> bool { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, + BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, + } + } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(AggregateKind<'_>, 48); - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum BinOp { - /// The `+` operator (addition) - Add, - /// The `-` operator (subtraction) - Sub, - /// The `*` operator (multiplication) - Mul, - /// The `/` operator (division) - /// - /// Division by zero is UB, because the compiler should have inserted checks - /// prior to this. - Div, - /// The `%` operator (modulus) - /// - /// Using zero as the modulus (second operand) is UB, because the compiler - /// should have inserted checks prior to this. - Rem, - /// The `^` operator (bitwise xor) - BitXor, - /// The `&` operator (bitwise and) - BitAnd, - /// The `|` operator (bitwise or) - BitOr, - /// The `<<` operator (shift left) - /// - /// The offset is truncated to the size of the first operand before shifting. - Shl, - /// The `>>` operator (shift right) - /// - /// The offset is truncated to the size of the first operand before shifting. - Shr, - /// The `==` operator (equality) - Eq, - /// The `<` operator (less than) - Lt, - /// The `<=` operator (less than or equal to) - Le, - /// The `!=` operator (not equal to) - Ne, - /// The `>=` operator (greater than or equal to) - Ge, - /// The `>` operator (greater than) - Gt, - /// The `ptr.offset` operator - Offset, + pub fn describe_mutability(&self) -> &str { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable", + BorrowKind::Mut { .. } => "mutable", + } + } } impl BinOp { @@ -2744,22 +1855,6 @@ impl BinOp { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum NullOp { - /// Returns the size of a value of that type - SizeOf, - /// Returns the minimum alignment of a type - AlignOf, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum UnOp { - /// The `!` operator for logical inversion - Not, - /// The `-` operator for negation - Neg, -} - impl<'tcx> Debug for Rvalue<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Rvalue::*; @@ -2795,7 +1890,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { // When printing regions, add trailing space if necessary. let print_region = ty::tls::with(|tcx| { - tcx.sess.verbose() || tcx.sess.opts.debugging_opts.identify_regions + tcx.sess.verbose() || tcx.sess.opts.unstable_opts.identify_regions }); let region = if print_region { let mut region = region.to_string(); @@ -2810,6 +1905,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { write!(fmt, "&{}{}{:?}", region, kind_str, place) } + CopyForDeref(ref place) => write!(fmt, "deref_copy {:#?}", place), + AddressOf(mutability, ref place) => { let kind_str = match mutability { Mutability::Mut => "mut", @@ -2863,7 +1960,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { if let Some(def_id) = def_id.as_local() { - let name = if tcx.sess.opts.debugging_opts.span_free_formats { + let name = if tcx.sess.opts.unstable_opts.span_free_formats { let substs = tcx.lift(substs).unwrap(); format!( "[closure@{}]", @@ -3115,7 +2212,7 @@ impl<'tcx> ConstantKind<'tcx> { #[inline] pub fn zero_sized(ty: Ty<'tcx>) -> Self { - let cv = ConstValue::Scalar(Scalar::ZST); + let cv = ConstValue::ZeroSized; Self::Val(cv, ty) } @@ -3340,7 +2437,7 @@ impl<'tcx> ConstantKind<'tcx> { /// The first will lead to the constraint `w: &'1 str` (for some /// inferred region `'1`). The second will lead to the constraint `w: /// &'static str`. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct UserTypeProjections { pub contents: Vec<(UserTypeProjection, Span)>, } @@ -3457,7 +2554,7 @@ impl UserTypeProjection { } } -TrivialTypeFoldableAndLiftImpls! { ProjectionKind, } +TrivialTypeTraversalAndLiftImpls! { ProjectionKind, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { @@ -3466,7 +2563,9 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { projs: self.projs.try_fold_with(folder)?, }) } +} +impl<'tcx> TypeVisitable<'tcx> for UserTypeProjection { fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> { self.base.visit_with(visitor) // Note: there's nothing in `self.proj` to visit. @@ -3689,6 +2788,13 @@ fn pretty_print_const_value<'tcx>( fmt.write_str(&cx.into_buffer())?; return Ok(()); } + (ConstValue::ZeroSized, ty::FnDef(d, s)) => { + let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); + cx.print_alloc_ids = true; + let cx = cx.print_value_path(*d, s)?; + fmt.write_str(&cx.into_buffer())?; + return Ok(()); + } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading // their fields instead of just dumping the memory. _ => {} @@ -3702,48 +2808,6 @@ fn pretty_print_const_value<'tcx>( }) } -impl<'tcx> graph::DirectedGraph for Body<'tcx> { - type Node = BasicBlock; -} - -impl<'tcx> graph::WithNumNodes for Body<'tcx> { - #[inline] - fn num_nodes(&self) -> usize { - self.basic_blocks.len() - } -} - -impl<'tcx> graph::WithStartNode for Body<'tcx> { - #[inline] - fn start_node(&self) -> Self::Node { - START_BLOCK - } -} - -impl<'tcx> graph::WithSuccessors for Body<'tcx> { - #[inline] - fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter { - self.basic_blocks[node].terminator().successors() - } -} - -impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { - type Item = BasicBlock; - type Iter = Successors<'b>; -} - -impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> { - type Item = BasicBlock; - type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>; -} - -impl<'tcx> graph::WithPredecessors for Body<'tcx> { - #[inline] - fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter { - self.predecessors()[node].iter().copied() - } -} - /// `Location` represents the position of the start of the statement; or, if /// `statement_index` equals the number of statements, then the start of the /// terminator. @@ -3780,7 +2844,7 @@ impl Location { return true; } - let predecessors = body.predecessors(); + let predecessors = body.basic_blocks.predecessors(); // If we're in another block, then we want to check that block is a predecessor of `other`. let mut queue: Vec<BasicBlock> = predecessors[other.block].to_vec(); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 021f278273646..8b51c5b3da50a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -90,7 +90,7 @@ impl<'tcx> MonoItem<'tcx> { let generate_cgu_internal_copies = tcx .sess .opts - .debugging_opts + .unstable_opts .inline_in_all_cgus .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code(); @@ -459,7 +459,7 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> { { let cgu_name = self.build_cgu_name_no_mangle(cnum, components, special_suffix); - if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names { + if self.tcx.sess.opts.unstable_opts.human_readable_cgu_names { cgu_name } else { Symbol::intern(&CodegenUnit::mangle_name(cgu_name.as_str())) diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs index 620cf7e336ba4..5f1fadaf3bc4c 100644 --- a/compiler/rustc_middle/src/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -73,6 +73,6 @@ impl<CTX> HashStable<CTX> for PredecessorCache { } } -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { PredecessorCache, } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 462c0ada3cf87..970043d427ff2 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -90,7 +90,7 @@ pub fn dump_mir<'tcx, F>( } pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool { - let Some(ref filters) = tcx.sess.opts.debugging_opts.dump_mir else { + let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir else { return false; }; // see notes on #41697 below @@ -141,7 +141,7 @@ fn dump_matched_mir_node<'tcx, F>( extra_data(PassWhere::AfterCFG, &mut file)?; }; - if tcx.sess.opts.debugging_opts.dump_mir_graphviz { + if tcx.sess.opts.unstable_opts.dump_mir_graphviz { let _: io::Result<()> = try { let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?; @@ -149,7 +149,7 @@ fn dump_matched_mir_node<'tcx, F>( }; } - if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { + if let Some(spanview) = tcx.sess.opts.unstable_opts.dump_mir_spanview { let _: io::Result<()> = try { let file_basename = dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source); @@ -175,7 +175,7 @@ fn dump_file_basename<'tcx>( None => String::new(), }; - let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number { + let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { String::new() } else { match pass_num { @@ -214,7 +214,7 @@ fn dump_file_basename<'tcx>( /// graphviz data or other things. fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { let mut file_path = PathBuf::new(); - file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); + file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); let file_name = format!("{}.{}", basename, extension,); @@ -448,7 +448,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { self.push(&format!("+ user_ty: {:?}", user_ty)); } + // FIXME: this is a poor version of `pretty_print_const_value`. let fmt_val = |val: &ConstValue<'tcx>| match val { + ConstValue::ZeroSized => format!("<ZST>"), ConstValue::Scalar(s) => format!("Scalar({:?})", s), ConstValue::Slice { .. } => format!("Slice(..)"), ConstValue::ByRef { .. } => format!("ByRef(..)"), @@ -679,6 +681,7 @@ pub fn write_allocations<'tcx>( ConstValue::Scalar(interpret::Scalar::Int { .. }) => { Either::Left(Either::Right(std::iter::empty())) } + ConstValue::ZeroSized => Either::Left(Either::Right(std::iter::empty())), ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => { Either::Right(alloc_ids_from_alloc(alloc)) } @@ -716,12 +719,12 @@ pub fn write_allocations<'tcx>( } write!(w, "{}", display_allocation(tcx, alloc.inner())) }; - write!(w, "\n{}", id)?; + write!(w, "\n{id:?}")?; match tcx.get_global_alloc(id) { // This can't really happen unless there are bugs, but it doesn't cost us anything to // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, - Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, + Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { match tcx.eval_static_initializer(did) { Ok(alloc) => { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index da4793fa039d0..6a6ed3dc728d9 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -35,7 +35,6 @@ pub enum UnsafetyViolationDetails { UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, - AssignToDroppingUnionField, AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, @@ -78,11 +77,6 @@ impl UnsafetyViolationDetails { "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), - AssignToDroppingUnionField => ( - "assignment to union field that might need dropping", - "the previous content of the field will be dropped, which causes undefined \ - behavior if the field was not properly initialized", - ), AccessToUnionField => ( "access to union field", "the field may not be properly initialized: using uninitialized data will cause \ @@ -161,7 +155,7 @@ rustc_index::newtype_index! { } /// The layout of generator state. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>, diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs index 99d13fcfef43e..d1f3e6b6fe6bd 100644 --- a/compiler/rustc_middle/src/mir/switch_sources.rs +++ b/compiler/rustc_middle/src/mir/switch_sources.rs @@ -73,6 +73,6 @@ impl<CTX> HashStable<CTX> for SwitchSourceCache { } } -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { SwitchSourceCache, } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs new file mode 100644 index 0000000000000..263c2ca3c700e --- /dev/null +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -0,0 +1,1174 @@ +//! This defines the syntax of MIR, i.e., the set of available MIR operations, and other definitions +//! closely related to MIR semantics. +//! This is in a dedicated file so that changes to this file can be reviewed more carefully. +//! The intention is that this file only contains datatype declarations, no code. + +use super::{BasicBlock, Constant, Field, Local, SwitchTargets, UserTypeProjection}; + +use crate::mir::coverage::{CodeRegion, CoverageKind}; +use crate::ty::adjustment::PointerCast; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, List, Ty}; +use crate::ty::{Region, UserTypeAnnotationIndex}; + +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir}; +use rustc_hir::{self, GeneratorKind}; +use rustc_target::abi::VariantIdx; + +use rustc_ast::Mutability; +use rustc_span::symbol::Symbol; +use rustc_span::Span; +use rustc_target::asm::InlineAsmRegOrRegClass; + +/// The various "big phases" that MIR goes through. +/// +/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the +/// dialects forbid certain variants or values in certain phases. The sections below summarize the +/// changes, but do not document them thoroughly. The full documentation is found in the appropriate +/// documentation for the thing the change is affecting. +/// +/// Warning: ordering of variants is significant. +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(HashStable)] +pub enum MirPhase { + /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also + /// the MIR that analysis such as borrowck uses. + /// + /// One important thing to remember about the behavior of this section of MIR is that drop terminators + /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each + /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop + /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize + /// when things are initialized and when things are de-initialized. That means any code running on this + /// version of MIR must be sure to produce output that drop elaboration can reason about. See the + /// section on the drop terminatorss for more details. + Built = 0, + // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query). + // We used to have this for pre-miri MIR based const eval. + Const = 1, + /// This phase checks the MIR for promotable elements and takes them out of the main MIR body + /// by creating a new MIR body per promoted element. After this phase (and thus the termination + /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` + /// query. + ConstsPromoted = 2, + /// After this projections may only contain deref projections as the first element. + Derefered = 3, + /// Beginning with this phase, the following variants are disallowed: + /// * [`TerminatorKind::DropAndReplace`] + /// * [`TerminatorKind::FalseUnwind`] + /// * [`TerminatorKind::FalseEdge`] + /// * [`StatementKind::FakeRead`] + /// * [`StatementKind::AscribeUserType`] + /// * [`Rvalue::Ref`] with `BorrowKind::Shallow` + /// + /// And the following variant is allowed: + /// * [`StatementKind::Retag`] + /// + /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` + /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands + /// are allowed for non-`Copy` types. + DropsLowered = 4, + /// Beginning with this phase, the following variant is disallowed: + /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` + /// + /// And the following variant is allowed: + /// * [`StatementKind::SetDiscriminant`] + Deaggregated = 5, + /// Before this phase, generators are in the "source code" form, featuring `yield` statements + /// and such. With this phase change, they are transformed into a proper state machine. Running + /// optimizations before this change can be potentially dangerous because the source code is to + /// some extent a "lie." In particular, `yield` terminators effectively make the value of all + /// locals visible to the caller. This means that dead store elimination before them, or code + /// motion across them, is not correct in general. This is also exasperated by type checking + /// having pre-computed a list of the types that it thinks are ok to be live across a yield + /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new + /// types across a yield point will lead to ICEs becaues of this. + /// + /// Beginning with this phase, the following variants are disallowed: + /// * [`TerminatorKind::Yield`] + /// * [`TerminatorKind::GeneratorDrop`] + /// * [`ProjectionElem::Deref`] of `Box` + GeneratorsLowered = 6, + Optimized = 7, +} + +/////////////////////////////////////////////////////////////////////////// +// Borrow kinds + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum BorrowKind { + /// Data must be immutable and is aliasable. + Shared, + + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. For example, a shallow borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + /// + /// This is used when lowering matches: when matching on a place we want to + /// ensure that place have the same value from the start of the match until + /// an arm is selected. This prevents this code from compiling: + /// ```compile_fail,E0510 + /// let mut x = &Some(0); + /// match *x { + /// None => (), + /// Some(_) if { x = &None; false } => (), + /// Some(_) => (), + /// } + /// ``` + /// This can't be a shared borrow because mutably borrowing (*x as Some).0 + /// should not prevent `if let None = x { ... }`, for example, because the + /// mutating `(*x as Some).0` can't affect the discriminant of `x`. + /// We can also report errors with this kind of borrow differently. + Shallow, + + /// Data must be immutable but not aliasable. This kind of borrow + /// cannot currently be expressed by the user and is used only in + /// implicit closure bindings. It is needed when the closure is + /// borrowing or mutating a mutable referent, e.g.: + /// ``` + /// let mut z = 3; + /// let x: &mut isize = &mut z; + /// let y = || *x += 5; + /// ``` + /// If we were to try to translate this closure into a more explicit + /// form, we'd encounter an error with the code as written: + /// ```compile_fail,E0594 + /// struct Env<'a> { x: &'a &'a mut isize } + /// let mut z = 3; + /// let x: &mut isize = &mut z; + /// let y = (&mut Env { x: &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// This is then illegal because you cannot mutate an `&mut` found + /// in an aliasable location. To solve, you'd have to translate with + /// an `&mut` borrow: + /// ```compile_fail,E0596 + /// struct Env<'a> { x: &'a mut &'a mut isize } + /// let mut z = 3; + /// let x: &mut isize = &mut z; + /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// Now the assignment to `**env.x` is legal, but creating a + /// mutable pointer to `x` is not because `x` is not mutable. We + /// could fix this by declaring `x` as `let mut x`. This is ok in + /// user code, if awkward, but extra weird for closures, since the + /// borrow is hidden. + /// + /// So we introduce a "unique imm" borrow -- the referent is + /// immutable, but not aliasable. This solves the problem. For + /// simplicity, we don't give users the way to express this + /// borrow, it's just used when translating closures. + Unique, + + /// Data is mutable and not aliasable. + Mut { + /// `true` if this borrow arose from method-call auto-ref + /// (i.e., `adjustment::Adjust::Borrow`). + allow_two_phase_borrow: bool, + }, +} + +/////////////////////////////////////////////////////////////////////////// +// Statements + +/// The various kinds of statements that can appear in MIR. +/// +/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which +/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions, +/// causing an ICE if they are violated. +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum StatementKind<'tcx> { + /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except + /// without the possibility of dropping the previous value (that must be done separately, if at + /// all). The *exact* way this works is undecided. It probably does something like evaluating + /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various + /// parts of this may do type specific things that are more complicated than simply copying + /// bytes. + /// + /// **Needs clarification**: The implication of the above idea would be that assignment implies + /// that the resulting value is initialized. I believe we could commit to this separately from + /// committing to whatever part of the memory model we would need to decide on to make the above + /// paragragh precise. Do we want to? + /// + /// Assignments in which the types of the place and rvalue differ are not well-formed. + /// + /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for + /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we + /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this + /// interesting for optimizations? Do we want to allow such optimizations? + /// + /// **Needs clarification**: We currently require that the LHS place not overlap with any place + /// read as part of computation of the RHS for some rvalues (generally those not producing + /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion, + /// it is also unclear in what order the components are evaluated. + /// + /// [#68364]: https://github.com/rust-lang/rust/issues/68364 + /// + /// See [`Rvalue`] documentation for details on each of those. + Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), + + /// This represents all the reading that a pattern match may do (e.g., inspecting constants and + /// discriminant values), and the kind of pattern it comes from. This is in order to adapt + /// potential error messages to these specific patterns. + /// + /// Note that this also is emitted for regular `let` bindings to ensure that locals that are + /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;` + /// + /// When executed at runtime this is a nop. + /// + /// Disallowed after drop elaboration. + FakeRead(Box<(FakeReadCause, Place<'tcx>)>), + + /// Write the discriminant for a variant to the enum Place. + /// + /// This is permitted for both generators and ADTs. This does not necessarily write to the + /// entire place; instead, it writes to the minimum set of bytes as required by the layout for + /// the type. + SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx }, + + /// Deinitializes the place. + /// + /// This writes `uninit` bytes to the entire place. + Deinit(Box<Place<'tcx>>), + + /// `StorageLive` and `StorageDead` statements mark the live range of a local. + /// + /// At any point during the execution of a function, each local is either allocated or + /// unallocated. Except as noted below, all locals except function parameters are initially + /// unallocated. `StorageLive` statements cause memory to be allocated for the local while + /// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only + /// reading/writing from it) while it is unallocated is UB. + /// + /// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body. + /// These locals are implicitly allocated for the full duration of the function. There is a + /// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for + /// computing these locals. + /// + /// If the local is already allocated, calling `StorageLive` again is UB. However, for an + /// unallocated local an additional `StorageDead` all is simply a nop. + StorageLive(Local), + + /// See `StorageLive` above. + StorageDead(Local), + + /// Retag references in the given place, ensuring they got fresh tags. + /// + /// This is part of the Stacked Borrows model. These statements are currently only interpreted + /// by miri and only generated when `-Z mir-emit-retag` is passed. See + /// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for + /// more details. + /// + /// For code that is not specific to stacked borrows, you should consider retags to read + /// and modify the place in an opaque way. + Retag(RetagKind, Box<Place<'tcx>>), + + /// Encodes a user's type ascription. These need to be preserved + /// intact so that NLL can respect them. For example: + /// ```ignore (illustrative) + /// let a: T = y; + /// ``` + /// The effect of this annotation is to relate the type `T_y` of the place `y` + /// to the user-given type `T`. The effect depends on the specified variance: + /// + /// - `Covariant` -- requires that `T_y <: T` + /// - `Contravariant` -- requires that `T_y :> T` + /// - `Invariant` -- requires that `T_y == T` + /// - `Bivariant` -- no effect + /// + /// When executed at runtime this is a nop. + /// + /// Disallowed after drop elaboration. + AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), + + /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A + /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage + /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates + /// executable code, to increment a counter variable at runtime, each time the code region is + /// executed. + Coverage(Box<Coverage>), + + /// Denotes a call to the intrinsic function `copy_nonoverlapping`. + /// + /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, + /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and + /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of + /// the `src` place are copied to the continguous range of bytes beginning with the first byte + /// of `dest`. + /// + /// **Needs clarification**: In what order are operands computed and dereferenced? It should + /// probably match the order for assignment, but that is also undecided. + /// + /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? + /// I vaguely remember Ralf saying somewhere that he thought it should not be. + CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>), + + /// No-op. Useful for deleting instructions without affecting statement indices. + Nop, +} + +/// Describes what kind of retag is to be performed. +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub enum RetagKind { + /// The initial retag when entering a function. + FnEntry, + /// Retag preparing for a two-phase borrow. + TwoPhase, + /// Retagging raw pointers. + Raw, + /// A "normal" retag. + Default, +} + +/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] +pub enum FakeReadCause { + /// Inject a fake read of the borrowed input at the end of each guards + /// code. + /// + /// This should ensure that you cannot change the variant for an enum while + /// you are in the midst of matching on it. + ForMatchGuard, + + /// `let x: !; match x {}` doesn't generate any read of x so we need to + /// generate a read of x to check that it is initialized and safe. + /// + /// If a closure pattern matches a Place starting with an Upvar, then we introduce a + /// FakeRead for that Place outside the closure, in such a case this option would be + /// Some(closure_def_id). + /// Otherwise, the value of the optional DefId will be None. + ForMatchedPlace(Option<DefId>), + + /// A fake read of the RefWithinGuard version of a bind-by-value variable + /// in a match guard to ensure that its value hasn't change by the time + /// we create the OutsideGuard version. + ForGuardBinding, + + /// Officially, the semantics of + /// + /// `let pattern = <expr>;` + /// + /// is that `<expr>` is evaluated into a temporary and then this temporary is + /// into the pattern. + /// + /// However, if we see the simple pattern `let var = <expr>`, we optimize this to + /// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable, + /// but in some cases it can affect the borrow checker, as in #53695. + /// Therefore, we insert a "fake read" here to ensure that we get + /// appropriate errors. + /// + /// If a closure pattern matches a Place starting with an Upvar, then we introduce a + /// FakeRead for that Place outside the closure, in such a case this option would be + /// Some(closure_def_id). + /// Otherwise, the value of the optional DefId will be None. + ForLet(Option<DefId>), + + /// If we have an index expression like + /// + /// (*x)[1][{ x = y; 4}] + /// + /// then the first bounds check is invalidated when we evaluate the second + /// index expression. Thus we create a fake borrow of `x` across the second + /// indexer, which will cause a borrow check error. + ForIndex, +} + +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct Coverage { + pub kind: CoverageKind, + pub code_region: Option<CodeRegion>, +} + +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct CopyNonOverlapping<'tcx> { + pub src: Operand<'tcx>, + pub dst: Operand<'tcx>, + /// Number of elements to copy from src to dest, not bytes. + pub count: Operand<'tcx>, +} + +/////////////////////////////////////////////////////////////////////////// +// Terminators + +/// The various kinds of terminators, representing ways of exiting from a basic block. +/// +/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the +/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such +/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then +/// once the current function is reached, execution continues at the given basic block, if any. If +/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is +/// equivalent to the execution of a `Resume` terminator. +/// +/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` +/// basic blocks have a couple restrictions: +/// 1. All `cleanup` fields in them must be `None`. +/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. +/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks +/// must also be `cleanup`. This is a part of the type system and checked statically, so it is +/// still an error to have such an edge in the CFG even if it's known that it won't be taken at +/// runtime. +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +pub enum TerminatorKind<'tcx> { + /// Block has one successor; we continue execution there. + Goto { target: BasicBlock }, + + /// Switches based on the computed value. + /// + /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned + /// integer, char, or bool, and must match the given type. Then, if the list of switch targets + /// contains the computed value, continues execution at the associated basic block. Otherwise, + /// continues execution at the "otherwise" basic block. + /// + /// Target values may not appear more than once. + SwitchInt { + /// The discriminant value being tested. + discr: Operand<'tcx>, + + /// The type of value being tested. + /// This is always the same as the type of `discr`. + /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. + switch_ty: Ty<'tcx>, + + targets: SwitchTargets, + }, + + /// Indicates that the landing pad is finished and that the process should continue unwinding. + /// + /// Like a return, this marks the end of this invocation of the function. + /// + /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after + /// deaggregation runs. + Resume, + + /// Indicates that the landing pad is finished and that the process should abort. + /// + /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in + /// cleanup blocks. + Abort, + + /// Returns from the function. + /// + /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very + /// likely at least assigns the value currently in the return place (`_0`) to the place + /// specified in the associated `Call` terminator in the calling function, as if assigned via + /// `dest = move _0`. It might additionally do other things, like have side-effects in the + /// aliasing model. + /// + /// If the body is a generator body, this has slightly different semantics; it instead causes a + /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned + /// to the return place. + Return, + + /// Indicates a terminator that can never be reached. + /// + /// Executing this terminator is UB. + Unreachable, + + /// The behavior of this statement differs significantly before and after drop elaboration. + /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which + /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop + /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an + /// issue tracking if drop glue has any interesting semantics in addition to those of a function + /// call?) + /// + /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the + /// `Drop` will be executed if... + /// + /// **Needs clarification**: End of that sentence. This in effect should document the exact + /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure: + /// + /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to + /// > the place or one of its "parents" occurred more recently than a move out of it. This does not + /// > consider indirect assignments. + Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, + + /// Drops the place and assigns a new value to it. + /// + /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator; + /// it then additionally assigns the `value` to the `place` as if by an assignment statement. + /// This assignment occurs both in the unwind and the regular code paths. The semantics are best + /// explained by the elaboration: + /// + /// ```ignore (MIR) + /// BB0 { + /// DropAndReplace(P <- V, goto BB1, unwind BB2) + /// } + /// ``` + /// + /// becomes + /// + /// ```ignore (MIR) + /// BB0 { + /// Drop(P, goto BB1, unwind BB2) + /// } + /// BB1 { + /// // P is now uninitialized + /// P <- V + /// } + /// BB2 { + /// // P is now uninitialized -- its dtor panicked + /// P <- V + /// } + /// ``` + /// + /// Disallowed after drop elaboration. + DropAndReplace { + place: Place<'tcx>, + value: Operand<'tcx>, + target: BasicBlock, + unwind: Option<BasicBlock>, + }, + + /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of + /// the referred to function. The operand types must match the argument types of the function. + /// The return place type must match the return type. The type of the `func` operand must be + /// callable, meaning either a function pointer, a function type, or a closure type. + /// + /// **Needs clarification**: The exact semantics of this. Current backends rely on `move` + /// operands not aliasing the return place. It is unclear how this is justified in MIR, see + /// [#71117]. + /// + /// [#71117]: https://github.com/rust-lang/rust/issues/71117 + Call { + /// The function that’s being called. + func: Operand<'tcx>, + /// Arguments the function is called with. + /// These are owned by the callee, which is free to modify them. + /// This allows the memory occupied by "by-value" arguments to be + /// reused across function calls without duplicating the contents. + args: Vec<Operand<'tcx>>, + /// Where the returned value will be written + destination: Place<'tcx>, + /// Where to go after this call returns. If none, the call necessarily diverges. + target: Option<BasicBlock>, + /// Cleanups to be done if the call unwinds. + cleanup: Option<BasicBlock>, + /// `true` if this is from a call in HIR rather than from an overloaded + /// operator. True for overloaded function call. + from_hir_call: bool, + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + fn_span: Span, + }, + + /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`, + /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some + /// unspecified constant as the function to call, all the operands stored in the `AssertMessage` + /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not + /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the + /// assertion does not fail, execution continues at the specified basic block. + Assert { + cond: Operand<'tcx>, + expected: bool, + msg: AssertMessage<'tcx>, + target: BasicBlock, + cleanup: Option<BasicBlock>, + }, + + /// Marks a suspend point. + /// + /// Like `Return` terminators in generator bodies, this computes `value` and then a + /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to + /// the return place of the function calling this one, and execution continues in the calling + /// function. When next invoked with the same first argument, execution of this function + /// continues at the `resume` basic block, with the second argument written to the `resume_arg` + /// place. If the generator is dropped before then, the `drop` basic block is invoked. + /// + /// Not permitted in bodies that are not generator bodies, or after generator lowering. + /// + /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`? + Yield { + /// The value to return. + value: Operand<'tcx>, + /// Where to resume to. + resume: BasicBlock, + /// The place to store the resume argument in. + resume_arg: Place<'tcx>, + /// Cleanup to be done if the generator is dropped at this suspend point. + drop: Option<BasicBlock>, + }, + + /// Indicates the end of dropping a generator. + /// + /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations + /// as `yield`. + /// + /// **Needs clarification**: Is that even correct? The generator drop code is always confusing + /// to me, because it's not even really in the current body. + /// + /// **Needs clarification**: Are there type system constraints on these terminators? Should + /// there be a "block type" like `cleanup` blocks for them? + GeneratorDrop, + + /// A block where control flow only ever takes one real path, but borrowck needs to be more + /// conservative. + /// + /// At runtime this is semantically just a goto. + /// + /// Disallowed after drop elaboration. + FalseEdge { + /// The target normal control flow will take. + real_target: BasicBlock, + /// A block control flow could conceptually jump to, but won't in + /// practice. + imaginary_target: BasicBlock, + }, + + /// A terminator for blocks that only take one path in reality, but where we reserve the right + /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops + /// with no function calls for example. + /// + /// At runtime this is semantically just a goto. + /// + /// Disallowed after drop elaboration. + FalseUnwind { + /// The target normal control flow will take. + real_target: BasicBlock, + /// The imaginary cleanup block link. This particular path will never be taken + /// in practice, but in order to avoid fragility we want to always + /// consider it in borrowck. We don't want to accept programs which + /// pass borrowck only when `panic=abort` or some assertions are disabled + /// due to release vs. debug mode builds. This needs to be an `Option` because + /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. + unwind: Option<BasicBlock>, + }, + + /// Block ends with an inline assembly block. This is a terminator since + /// inline assembly is allowed to diverge. + InlineAsm { + /// The template for the inline assembly, with placeholders. + template: &'tcx [InlineAsmTemplatePiece], + + /// The operands for the inline assembly, as `Operand`s or `Place`s. + operands: Vec<InlineAsmOperand<'tcx>>, + + /// Miscellaneous options for the inline assembly. + options: InlineAsmOptions, + + /// Source spans for each line of the inline assembly code. These are + /// used to map assembler errors back to the line in the source code. + line_spans: &'tcx [Span], + + /// Destination block after the inline assembly returns, unless it is + /// diverging (InlineAsmOptions::NORETURN). + destination: Option<BasicBlock>, + + /// Cleanup to be done if the inline assembly unwinds. This is present + /// if and only if InlineAsmOptions::MAY_UNWIND is set. + cleanup: Option<BasicBlock>, + }, +} + +/// Information about an assertion failure. +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] +pub enum AssertKind<O> { + BoundsCheck { len: O, index: O }, + Overflow(BinOp, O, O), + OverflowNeg(O), + DivisionByZero(O), + RemainderByZero(O), + ResumedAfterReturn(GeneratorKind), + ResumedAfterPanic(GeneratorKind), +} + +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum InlineAsmOperand<'tcx> { + In { + reg: InlineAsmRegOrRegClass, + value: Operand<'tcx>, + }, + Out { + reg: InlineAsmRegOrRegClass, + late: bool, + place: Option<Place<'tcx>>, + }, + InOut { + reg: InlineAsmRegOrRegClass, + late: bool, + in_value: Operand<'tcx>, + out_place: Option<Place<'tcx>>, + }, + Const { + value: Box<Constant<'tcx>>, + }, + SymFn { + value: Box<Constant<'tcx>>, + }, + SymStatic { + def_id: DefId, + }, +} + +/// Type for MIR `Assert` terminator error messages. +pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; + +/////////////////////////////////////////////////////////////////////////// +// Places + +/// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical +/// object as places in Rust. This of course means that what exactly they are is undecided and part +/// of the Rust memory model. However, they will likely contain at least the following pieces of +/// information in some form: +/// +/// 1. The address in memory that the place refers to. +/// 2. The provenance with which the place is being accessed. +/// 3. The type of the place and an optional variant index. See [`PlaceTy`][super::tcx::PlaceTy]. +/// 4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`. +/// +/// We'll give a description below of how all pieces of the place except for the provenance are +/// calculated. We cannot give a description of the provenance, because that is part of the +/// undecided aliasing model - we only include it here at all to acknowledge its existence. +/// +/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has +/// the address of the local's allocation and the type of the local. +/// +/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation +/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation. +/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under +/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and +/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into +/// the current MIR semantics in a clean way - possibly this needs some design work first. +/// +/// For places that are not locals, ie they have a non-empty list of projections, we define the +/// values as a function of the parent place, that is the place with its last [`ProjectionElem`] +/// stripped. The way this is computed of course depends on the kind of that last projection +/// element: +/// +/// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the +/// given one, and makes no other changes. A `Downcast` projection on a place with its variant +/// index already set is not well-formed. +/// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a +/// place referring to one of the fields of the type. The resulting address is the parent +/// address, plus the offset of the field. The type becomes the type of the field. If the parent +/// was unsized and so had metadata associated with it, then the metadata is retained if the +/// field is unsized and thrown out if it is sized. +/// +/// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or +/// generator has more than one variant, the parent place's variant index must be set, indicating +/// which variant is being used. If it has just one variant, the variant index may or may not be +/// included - the single possible variant is inferred if it is not included. +/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the +/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an +/// opaque type from the current crate is not well-formed. +/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the +/// place as described in the documentation for the `ProjectionElem`. The resulting address is +/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent +/// place has type `[T; N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any +/// resulting metadata is thrown out. +/// - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new +/// address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`. +/// However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the +/// length of the subslice. +/// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`. +/// However, `Index` additionally takes a local from which the value of the index is computed at +/// runtime. Computing the value of the index involves interpreting the `Local` as a +/// `Place { local, projection: [] }`, and then computing its value as if done via +/// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must +/// have type `usize`. +/// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most +/// complicated. They are only legal on parent places that are references, pointers, or `Box`. A +/// `Deref` projection begins by loading a value from the parent place, as if by +/// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the +/// pointee's type. The resulting address is the address that was stored in the pointer. If the +/// pointee type is unsized, the pointer additionally stored the value of the metadata. +/// +/// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not +/// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not +/// point to an actual allocation. +/// +/// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed +/// in [UCG#319]. The options include that every place must obey those rules, that only some places +/// must obey them, or that places impose no rules of their own. +/// +/// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319 +/// +/// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken +/// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)] +pub struct Place<'tcx> { + pub local: Local, + + /// projection out of a place (access a field, deref a pointer, etc) + pub projection: &'tcx List<PlaceElem<'tcx>>, +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Place<'_>, 16); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(TyEncodable, TyDecodable, HashStable)] +pub enum ProjectionElem<V, T> { + Deref, + Field(Field, T), + /// Index into a slice/array. + /// + /// Note that this does not also dereference, and so it does not exactly correspond to slice + /// indexing in Rust. In other words, in the below Rust code: + /// + /// ```rust + /// let x = &[1, 2, 3, 4]; + /// let i = 2; + /// x[i]; + /// ``` + /// + /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same + /// thing is true of the `ConstantIndex` and `Subslice` projections below. + Index(V), + + /// These indices are generated by slice patterns. Easiest to explain + /// by example: + /// + /// ```ignore (illustrative) + /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, + /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, + /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, + /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, + /// ``` + ConstantIndex { + /// index or -index (in Python terms), depending on from_end + offset: u64, + /// The thing being indexed must be at least this long. For arrays this + /// is always the exact length. + min_length: u64, + /// Counting backwards from end? This is always false when indexing an + /// array. + from_end: bool, + }, + + /// These indices are generated by slice patterns. + /// + /// If `from_end` is true `slice[from..slice.len() - to]`. + /// Otherwise `array[from..to]`. + Subslice { + from: u64, + to: u64, + /// Whether `to` counts from the start or end of the array/slice. + /// For `PlaceElem`s this is `true` if and only if the base is a slice. + /// For `ProjectionKind`, this can also be `true` for arrays. + from_end: bool, + }, + + /// "Downcast" to a variant of an enum or a generator. + /// + /// The included Symbol is the name of the variant, used for printing MIR. + Downcast(Option<Symbol>, VariantIdx), + + /// Like an explicit cast from an opaque type to a concrete type, but without + /// requiring an intermediate variable. + OpaqueCast(T), +} + +/// Alias for projections as they appear in places, where the base is a place +/// and the index is a local. +pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; + +// This type is fairly frequently used, so we shouldn't unintentionally increase +// its size. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(PlaceElem<'_>, 24); + +/////////////////////////////////////////////////////////////////////////// +// Operands + +/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of +/// the memory model. One proposal for a definition of values can be found [on UCG][value-def]. +/// +/// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md +/// +/// The most common way to create values is via loading a place. Loading a place is an operation +/// which reads the memory of the place and converts it to a value. This is a fundamentally *typed* +/// operation. The nature of the value produced depends on the type of the conversion. Furthermore, +/// there may be other effects: if the type has a validity constraint loading the place might be UB +/// if the validity constraint is not met. +/// +/// **Needs clarification:** Ralf proposes that loading a place not have side-effects. +/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this +/// something we can even decide without knowing more about Rust's memory model? +/// +/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri +/// currently implements it, but it seems like this may be something to check against in the +/// validator. +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum Operand<'tcx> { + /// Creates a value by loading the given place. + /// + /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there + /// is no such requirement. + Copy(Place<'tcx>), + + /// Creates a value by performing loading the place, just like the `Copy` operand. + /// + /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide + /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this + /// place without first re-initializing it. + /// + /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188 + Move(Place<'tcx>), + + /// Constants are already semantically values, and remain unchanged. + Constant(Box<Constant<'tcx>>), +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Operand<'_>, 24); + +/////////////////////////////////////////////////////////////////////////// +// Rvalues + +/// The various kinds of rvalues that can appear in MIR. +/// +/// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below. +/// +/// Computing any rvalue begins by evaluating the places and operands in some order (**Needs +/// clarification**: Which order?). These are then used to produce a "value" - the same kind of +/// value that an [`Operand`] produces. +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +pub enum Rvalue<'tcx> { + /// Yields the operand unchanged + Use(Operand<'tcx>), + + /// Creates an array where each element is the value of the operand. + /// + /// This is the cause of a bug in the case where the repetition count is zero because the value + /// is not dropped, see [#74836]. + /// + /// Corresponds to source code like `[x; 32]`. + /// + /// [#74836]: https://github.com/rust-lang/rust/issues/74836 + Repeat(Operand<'tcx>, ty::Const<'tcx>), + + /// Creates a reference of the indicated kind to the place. + /// + /// There is not much to document here, because besides the obvious parts the semantics of this + /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing + /// exactly what the behavior of this operation should be. + /// + /// `Shallow` borrows are disallowed after drop lowering. + Ref(Region<'tcx>, BorrowKind, Place<'tcx>), + + /// Creates a pointer/reference to the given thread local. + /// + /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a + /// `*const T`, and if neither of those apply a `&T`. + /// + /// **Note:** This is a runtime operation that actually executes code and is in this sense more + /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to + /// SIGILL for some reason that I (JakobDegen) never got a chance to look into. + /// + /// **Needs clarification**: Are there weird additional semantics here related to the runtime + /// nature of this operation? + ThreadLocalRef(DefId), + + /// Creates a pointer with the indicated mutability to the place. + /// + /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like + /// `&raw v` or `addr_of!(v)`. + /// + /// Like with references, the semantics of this operation are heavily dependent on the aliasing + /// model. + AddressOf(Mutability, Place<'tcx>), + + /// Yields the length of the place, as a `usize`. + /// + /// If the type of the place is an array, this is the array length. For slices (`[T]`, not + /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is + /// ill-formed for places of other types. + Len(Place<'tcx>), + + /// Performs essentially all of the casts that can be performed via `as`. + /// + /// This allows for casts from/to a variety of types. + /// + /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why + /// `ArrayToPointer` and `MutToConstPointer` are special. + Cast(CastKind, Operand<'tcx>, Ty<'tcx>), + + /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second + /// parameter may be a `usize` as well. + /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + /// matching, up to the usual caveat of the lifetimes in function pointers. + /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + /// truncated as needed. + /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + /// types and return a value of that type. + /// * The remaining operations accept signed integers, unsigned integers, or floats with + /// matching types and return a value of that type. + BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), + + /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. + /// + /// When overflow checking is disabled and we are generating run-time code, the error condition + /// is false. Otherwise, and always during CTFE, the error condition is determined as described + /// below. + /// + /// For addition, subtraction, and multiplication on integers the error condition is set when + /// the infinite precision result would be unequal to the actual result. + /// + /// For shift operations on integers the error condition is set when the value of right-hand + /// side is greater than or equal to the number of bits in the type of the left-hand side, or + /// when the value of right-hand side is negative. + /// + /// Other combinations of types and operators are unsupported. + CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), + + /// Computes a value as described by the operation. + NullaryOp(NullOp, Ty<'tcx>), + + /// Exactly like `BinaryOp`, but less operands. + /// + /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; + /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds + /// return a value with the same type as their operand. + UnaryOp(UnOp, Operand<'tcx>), + + /// Computes the discriminant of the place, returning it as an integer of type + /// [`discriminant_ty`]. Returns zero for types without discriminant. + /// + /// The validity requirements for the underlying value are undecided for this rvalue, see + /// [#91095]. Note too that the value of the discriminant is not the same thing as the + /// variant index; use [`discriminant_for_variant`] to convert. + /// + /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty + /// [#91095]: https://github.com/rust-lang/rust/issues/91095 + /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant + Discriminant(Place<'tcx>), + + /// Creates an aggregate value, like a tuple or struct. + /// + /// This is needed because dataflow analysis needs to distinguish + /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo` + /// has a destructor. + /// + /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After + /// generator lowering, `Generator` aggregate kinds are disallowed too. + Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>), + + /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. + /// + /// This is different from a normal transmute because dataflow analysis will treat the box as + /// initialized but its content as uninitialized. Like other pointer casts, this in general + /// affects alias analysis. + ShallowInitBox(Operand<'tcx>, Ty<'tcx>), + + /// A CopyForDeref is equivalent to a read from a place at the + /// codegen level, but is treated specially by drop elaboration. When such a read happens, it + /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) + /// that the only use of the returned value is a deref operation, immediately + /// followed by one or more projections. Drop elaboration treats this rvalue as if the + /// read never happened and just projects further. This allows simplifying various MIR + /// optimizations and codegen backends that previously had to handle deref operations anywhere + /// in a place. + CopyForDeref(Place<'tcx>), +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Rvalue<'_>, 40); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum CastKind { + /// An exposing pointer to address cast. A cast between a pointer and an integer type, or + /// between a function pointer and an integer type. + /// See the docs on `expose_addr` for more details. + PointerExposeAddress, + /// An address-to-pointer cast that picks up an exposed provenance. + /// See the docs on `from_exposed_addr` for more details. + PointerFromExposedAddress, + /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are + /// translated into `&raw mut/const *r`, i.e., they are not actually casts. + Pointer(PointerCast), + /// Remaining unclassified casts. + Misc, +} + +#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum AggregateKind<'tcx> { + /// The type is of the element + Array(Ty<'tcx>), + Tuple, + + /// The second field is the variant index. It's equal to 0 for struct + /// and union expressions. The fourth field is + /// 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` + Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), + + Closure(DefId, SubstsRef<'tcx>), + Generator(DefId, SubstsRef<'tcx>, hir::Movability), +} + +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(AggregateKind<'_>, 48); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum NullOp { + /// Returns the size of a value of that type + SizeOf, + /// Returns the minimum alignment of a type + AlignOf, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum UnOp { + /// The `!` operator for logical inversion + Not, + /// The `-` operator for negation + Neg, +} + +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum BinOp { + /// The `+` operator (addition) + Add, + /// The `-` operator (subtraction) + Sub, + /// The `*` operator (multiplication) + Mul, + /// The `/` operator (division) + /// + /// Division by zero is UB, because the compiler should have inserted checks + /// prior to this. + Div, + /// The `%` operator (modulus) + /// + /// Using zero as the modulus (second operand) is UB, because the compiler + /// should have inserted checks prior to this. + Rem, + /// The `^` operator (bitwise xor) + BitXor, + /// The `&` operator (bitwise and) + BitAnd, + /// The `|` operator (bitwise or) + BitOr, + /// The `<<` operator (shift left) + /// + /// The offset is truncated to the size of the first operand before shifting. + Shl, + /// The `>>` operator (shift right) + /// + /// The offset is truncated to the size of the first operand before shifting. + Shr, + /// The `==` operator (equality) + Eq, + /// The `<` operator (less than) + Lt, + /// The `<=` operator (less than or equal to) + Le, + /// The `!=` operator (not equal to) + Ne, + /// The `>=` operator (greater than or equal to) + Ge, + /// The `>` operator (greater than) + Gt, + /// The `ptr.offset` operator + Offset, +} diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index c93b7a9550229..c6975df45efc2 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -9,7 +9,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_target::abi::VariantIdx; -#[derive(Copy, Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct PlaceTy<'tcx> { pub ty: Ty<'tcx>, /// Downcast to a particular variant of an enum or a generator, if included. @@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> { /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty) + self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -71,6 +71,7 @@ impl<'tcx> PlaceTy<'tcx> { param_env: ty::ParamEnv<'tcx>, elem: &ProjectionElem<V, T>, mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, + mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where V: ::std::fmt::Debug, @@ -109,6 +110,7 @@ impl<'tcx> PlaceTy<'tcx> { PlaceTy { ty: self.ty, variant_index: Some(index) } } ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), + ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)), }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer @@ -211,6 +213,7 @@ impl<'tcx> Rvalue<'tcx> { } }, Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), + Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, } } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index c65e79a80fb8e..9ccf5aea63ca8 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -1,16 +1,12 @@ use crate::mir; use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use smallvec::{smallvec, SmallVec}; -use super::{ - AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors, - SuccessorsMut, -}; +use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind}; +use rustc_ast::InlineAsmTemplatePiece; pub use rustc_ast::Mutability; use rustc_macros::HashStable; -use rustc_span::Span; use std::borrow::Cow; use std::fmt::{self, Debug, Formatter, Write}; use std::iter; @@ -106,278 +102,16 @@ impl<'a> Iterator for SwitchTargetsIter<'a> { impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {} -/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the -/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such -/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then -/// once the current function is reached, execution continues at the given basic block, if any. If -/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is -/// equivalent to the execution of a `Resume` terminator. -/// -/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup` -/// basic blocks have a couple restrictions: -/// 1. All `cleanup` fields in them must be `None`. -/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are. -/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks -/// must also be `cleanup`. This is a part of the type system and checked statically, so it is -/// still an error to have such an edge in the CFG even if it's known that it won't be taken at -/// runtime. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] -pub enum TerminatorKind<'tcx> { - /// Block has one successor; we continue execution there. - Goto { target: BasicBlock }, - - /// Switches based on the computed value. - /// - /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned - /// integer, char, or bool, and must match the given type. Then, if the list of switch targets - /// contains the computed value, continues execution at the associated basic block. Otherwise, - /// continues execution at the "otherwise" basic block. - /// - /// Target values may not appear more than once. - SwitchInt { - /// The discriminant value being tested. - discr: Operand<'tcx>, - - /// The type of value being tested. - /// This is always the same as the type of `discr`. - /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. - switch_ty: Ty<'tcx>, - - targets: SwitchTargets, - }, - - /// Indicates that the landing pad is finished and that the process should continue unwinding. - /// - /// Like a return, this marks the end of this invocation of the function. - /// - /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after - /// deaggregation runs. - Resume, - - /// Indicates that the landing pad is finished and that the process should abort. - /// - /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in - /// cleanup blocks. - Abort, - - /// Returns from the function. - /// - /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very - /// likely at least assigns the value currently in the return place (`_0`) to the place - /// specified in the associated `Call` terminator in the calling function, as if assigned via - /// `dest = move _0`. It might additionally do other things, like have side-effects in the - /// aliasing model. - /// - /// If the body is a generator body, this has slightly different semantics; it instead causes a - /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned - /// to the return place. - Return, - - /// Indicates a terminator that can never be reached. - /// - /// Executing this terminator is UB. - Unreachable, - - /// The behavior of this statement differs significantly before and after drop elaboration. - /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which - /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop - /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an - /// issue tracking if drop glue has any interesting semantics in addition to those of a function - /// call?) - /// - /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the - /// `Drop` will be executed if... - /// - /// **Needs clarification**: End of that sentence. This in effect should document the exact - /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure: - /// - /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to - /// > the place or one of its "parents" occurred more recently than a move out of it. This does not - /// > consider indirect assignments. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, - - /// Drops the place and assigns a new value to it. - /// - /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator; - /// it then additionally assigns the `value` to the `place` as if by an assignment statement. - /// This assignment occurs both in the unwind and the regular code paths. The semantics are best - /// explained by the elaboration: - /// - /// ```ignore (MIR) - /// BB0 { - /// DropAndReplace(P <- V, goto BB1, unwind BB2) - /// } - /// ``` - /// - /// becomes - /// - /// ```ignore (MIR) - /// BB0 { - /// Drop(P, goto BB1, unwind BB2) - /// } - /// BB1 { - /// // P is now uninitialized - /// P <- V - /// } - /// BB2 { - /// // P is now uninitialized -- its dtor panicked - /// P <- V - /// } - /// ``` - /// - /// Disallowed after drop elaboration. - DropAndReplace { - place: Place<'tcx>, - value: Operand<'tcx>, - target: BasicBlock, - unwind: Option<BasicBlock>, - }, - - /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of - /// the referred to function. The operand types must match the argument types of the function. - /// The return place type must match the return type. The type of the `func` operand must be - /// callable, meaning either a function pointer, a function type, or a closure type. - /// - /// **Needs clarification**: The exact semantics of this. Current backends rely on `move` - /// operands not aliasing the return place. It is unclear how this is justified in MIR, see - /// [#71117]. - /// - /// [#71117]: https://github.com/rust-lang/rust/issues/71117 - Call { - /// The function that’s being called. - func: Operand<'tcx>, - /// Arguments the function is called with. - /// These are owned by the callee, which is free to modify them. - /// This allows the memory occupied by "by-value" arguments to be - /// reused across function calls without duplicating the contents. - args: Vec<Operand<'tcx>>, - /// Where the returned value will be written - destination: Place<'tcx>, - /// Where to go after this call returns. If none, the call necessarily diverges. - target: Option<BasicBlock>, - /// Cleanups to be done if the call unwinds. - cleanup: Option<BasicBlock>, - /// `true` if this is from a call in HIR rather than from an overloaded - /// operator. True for overloaded function call. - from_hir_call: bool, - /// This `Span` is the span of the function, without the dot and receiver - /// (e.g. `foo(a, b)` in `x.foo(a, b)` - fn_span: Span, - }, - - /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`, - /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some - /// unspecified constant as the function to call, all the operands stored in the `AssertMessage` - /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not - /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the - /// assertion does not fail, execution continues at the specified basic block. - Assert { - cond: Operand<'tcx>, - expected: bool, - msg: AssertMessage<'tcx>, - target: BasicBlock, - cleanup: Option<BasicBlock>, - }, - - /// Marks a suspend point. - /// - /// Like `Return` terminators in generator bodies, this computes `value` and then a - /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to - /// the return place of the function calling this one, and execution continues in the calling - /// function. When next invoked with the same first argument, execution of this function - /// continues at the `resume` basic block, with the second argument written to the `resume_arg` - /// place. If the generator is dropped before then, the `drop` basic block is invoked. - /// - /// Not permitted in bodies that are not generator bodies, or after generator lowering. - /// - /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`? - Yield { - /// The value to return. - value: Operand<'tcx>, - /// Where to resume to. - resume: BasicBlock, - /// The place to store the resume argument in. - resume_arg: Place<'tcx>, - /// Cleanup to be done if the generator is dropped at this suspend point. - drop: Option<BasicBlock>, - }, - - /// Indicates the end of dropping a generator. - /// - /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations - /// as `yield`. - /// - /// **Needs clarification**: Is that even correct? The generator drop code is always confusing - /// to me, because it's not even really in the current body. - /// - /// **Needs clarification**: Are there type system constraints on these terminators? Should - /// there be a "block type" like `cleanup` blocks for them? - GeneratorDrop, - - /// A block where control flow only ever takes one real path, but borrowck needs to be more - /// conservative. - /// - /// At runtime this is semantically just a goto. - /// - /// Disallowed after drop elaboration. - FalseEdge { - /// The target normal control flow will take. - real_target: BasicBlock, - /// A block control flow could conceptually jump to, but won't in - /// practice. - imaginary_target: BasicBlock, - }, - - /// A terminator for blocks that only take one path in reality, but where we reserve the right - /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops - /// with no function calls for example. - /// - /// At runtime this is semantically just a goto. - /// - /// Disallowed after drop elaboration. - FalseUnwind { - /// The target normal control flow will take. - real_target: BasicBlock, - /// The imaginary cleanup block link. This particular path will never be taken - /// in practice, but in order to avoid fragility we want to always - /// consider it in borrowck. We don't want to accept programs which - /// pass borrowck only when `panic=abort` or some assertions are disabled - /// due to release vs. debug mode builds. This needs to be an `Option` because - /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes. - unwind: Option<BasicBlock>, - }, - - /// Block ends with an inline assembly block. This is a terminator since - /// inline assembly is allowed to diverge. - InlineAsm { - /// The template for the inline assembly, with placeholders. - template: &'tcx [InlineAsmTemplatePiece], - - /// The operands for the inline assembly, as `Operand`s or `Place`s. - operands: Vec<InlineAsmOperand<'tcx>>, - - /// Miscellaneous options for the inline assembly. - options: InlineAsmOptions, - - /// Source spans for each line of the inline assembly code. These are - /// used to map assembler errors back to the line in the source code. - line_spans: &'tcx [Span], - - /// Destination block after the inline assembly returns, unless it is - /// diverging (InlineAsmOptions::NORETURN). - destination: Option<BasicBlock>, - - /// Cleanup to be done if the inline assembly unwinds. This is present - /// if and only if InlineAsmOptions::MAY_UNWIND is set. - cleanup: Option<BasicBlock>, - }, -} #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct Terminator<'tcx> { pub source_info: SourceInfo, pub kind: TerminatorKind<'tcx>, } +pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a; +pub type SuccessorsMut<'a> = + iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; + impl<'tcx> Terminator<'tcx> { pub fn successors(&self) -> Successors<'_> { self.kind.successors() diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 7228e3f33b126..627dc32f37eb5 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -104,22 +104,25 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// /// A Postorder traversal of this graph is `D B C A` or `D C B A` pub struct Postorder<'a, 'tcx> { - body: &'a Body<'tcx>, + basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>, visited: BitSet<BasicBlock>, visit_stack: Vec<(BasicBlock, Successors<'a>)>, root_is_start_block: bool, } impl<'a, 'tcx> Postorder<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { + pub fn new( + basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>, + root: BasicBlock, + ) -> Postorder<'a, 'tcx> { let mut po = Postorder { - body, - visited: BitSet::new_empty(body.basic_blocks().len()), + basic_blocks, + visited: BitSet::new_empty(basic_blocks.len()), visit_stack: Vec::new(), root_is_start_block: root == START_BLOCK, }; - let data = &po.body[root]; + let data = &po.basic_blocks[root]; if let Some(ref term) = data.terminator { po.visited.insert(root); @@ -190,7 +193,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { }; if self.visited.insert(bb) { - if let Some(term) = &self.body[bb].terminator { + if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); } } @@ -199,7 +202,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { } pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> { - Postorder::new(body, START_BLOCK) + Postorder::new(&body.basic_blocks, START_BLOCK) } impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { @@ -211,12 +214,12 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { self.traverse_successor(); } - next.map(|(bb, _)| (bb, &self.body[bb])) + next.map(|(bb, _)| (bb, &self.basic_blocks[bb])) } fn size_hint(&self) -> (usize, Option<usize>) { // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks().len() - self.visited.count(); + let upper = self.basic_blocks.len() - self.visited.count(); let lower = if self.root_is_start_block { // We will visit all remaining blocks exactly once. @@ -263,10 +266,8 @@ pub struct ReversePostorder<'a, 'tcx> { impl<'a, 'tcx> ReversePostorder<'a, 'tcx> { pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> { - let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect(); - + let blocks: Vec<_> = Postorder::new(&body.basic_blocks, root).map(|(bb, _)| bb).collect(); let len = blocks.len(); - ReversePostorder { body, blocks, idx: len } } } @@ -334,10 +335,8 @@ impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> { impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {} pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> { - let blocks = body.postorder_cache.compute(body); - + let blocks = body.basic_blocks.postorder(); let len = blocks.len(); - ReversePostorderIter { body, blocks, idx: len } } @@ -360,7 +359,7 @@ impl PostorderCache { /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR. #[inline] - pub(super) fn compute(&self, body: &Body<'_>) -> &[BasicBlock] { + pub(super) fn compute(&self, body: &IndexVec<BasicBlock, BasicBlockData<'_>>) -> &[BasicBlock] { self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect()) } } @@ -384,6 +383,6 @@ impl<CTX> HashStable<CTX> for PostorderCache { } } -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { PostorderCache, } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 4201b2d11ce2a..a73ef23e28132 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -4,7 +4,7 @@ use super::*; use crate::ty; use rustc_data_structures::functor::IdFunctor; -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { BlockTailInfo, MirPhase, SourceInfo, @@ -89,65 +89,12 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }; Ok(Terminator { source_info: self.source_info, kind }) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - use crate::mir::TerminatorKind::*; - - match self.kind { - SwitchInt { ref discr, switch_ty, .. } => { - discr.visit_with(visitor)?; - switch_ty.visit_with(visitor) - } - Drop { ref place, .. } => place.visit_with(visitor), - DropAndReplace { ref place, ref value, .. } => { - place.visit_with(visitor)?; - value.visit_with(visitor) - } - Yield { ref value, .. } => value.visit_with(visitor), - Call { ref func, ref args, ref destination, .. } => { - destination.visit_with(visitor)?; - func.visit_with(visitor)?; - args.visit_with(visitor) - } - Assert { ref cond, ref msg, .. } => { - cond.visit_with(visitor)?; - use AssertKind::*; - match msg { - BoundsCheck { ref len, ref index } => { - len.visit_with(visitor)?; - index.visit_with(visitor) - } - Overflow(_, l, r) => { - l.visit_with(visitor)?; - r.visit_with(visitor) - } - OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { - op.visit_with(visitor) - } - ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE, - } - } - InlineAsm { ref operands, .. } => operands.visit_with(visitor), - Goto { .. } - | Resume - | Abort - | Return - | GeneratorDrop - | Unreachable - | FalseEdge { .. } - | FalseUnwind { .. } => ControlFlow::CONTINUE, - } - } } impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { Ok(self) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { - ControlFlow::CONTINUE - } } impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { @@ -157,21 +104,12 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { projection: self.projection.try_fold_with(folder)?, }) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.local.visit_with(visitor)?; - self.projection.visit_with(visitor) - } } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v)) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.iter().try_for_each(|t| t.visit_with(visitor)) - } } impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { @@ -184,6 +122,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { Ref(region, bk, place) => { Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?) } + CopyForDeref(place) => CopyForDeref(place.try_fold_with(folder)?), AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?), Len(place) => Len(place.try_fold_with(folder)?), Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?), @@ -224,55 +163,6 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } }) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - use crate::mir::Rvalue::*; - match *self { - Use(ref op) => op.visit_with(visitor), - Repeat(ref op, _) => op.visit_with(visitor), - ThreadLocalRef(did) => did.visit_with(visitor), - Ref(region, _, ref place) => { - region.visit_with(visitor)?; - place.visit_with(visitor) - } - AddressOf(_, ref place) => place.visit_with(visitor), - Len(ref place) => place.visit_with(visitor), - Cast(_, ref op, ty) => { - op.visit_with(visitor)?; - ty.visit_with(visitor) - } - BinaryOp(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (ref rhs, ref lhs)) => { - rhs.visit_with(visitor)?; - lhs.visit_with(visitor) - } - UnaryOp(_, ref val) => val.visit_with(visitor), - Discriminant(ref place) => place.visit_with(visitor), - NullaryOp(_, ty) => ty.visit_with(visitor), - Aggregate(ref kind, ref fields) => { - match **kind { - AggregateKind::Array(ty) => { - ty.visit_with(visitor)?; - } - AggregateKind::Tuple => {} - AggregateKind::Adt(_, _, substs, user_ty, _) => { - substs.visit_with(visitor)?; - user_ty.visit_with(visitor)?; - } - AggregateKind::Closure(_, substs) => { - substs.visit_with(visitor)?; - } - AggregateKind::Generator(_, substs, _) => { - substs.visit_with(visitor)?; - } - } - fields.visit_with(visitor) - } - ShallowInitBox(ref op, ty) => { - op.visit_with(visitor)?; - ty.visit_with(visitor) - } - } - } } impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { @@ -283,13 +173,6 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?), }) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - match *self { - Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), - Operand::Constant(ref c) => c.visit_with(visitor), - } - } } impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { @@ -299,6 +182,7 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { Ok(match self { Deref => Deref, Field(f, ty) => Field(f, ty.try_fold_with(folder)?), + OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?), Index(v) => Index(v.try_fold_with(folder)?), Downcast(symbol, variantidx) => Downcast(symbol, variantidx), ConstantIndex { offset, min_length, from_end } => { @@ -307,43 +191,24 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { Subslice { from, to, from_end } => Subslice { from, to, from_end }, }) } - - fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> { - use crate::mir::ProjectionElem::*; - - match self { - Field(_, ty) => ty.visit_with(visitor), - Index(v) => v.visit_with(visitor), - _ => ControlFlow::CONTINUE, - } - } } impl<'tcx> TypeFoldable<'tcx> for Field { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { Ok(self) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { - ControlFlow::CONTINUE - } } impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { Ok(self) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { - ControlFlow::CONTINUE - } } impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { Ok(self) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { - ControlFlow::CONTINUE - } } impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { @@ -354,10 +219,6 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { literal: self.literal.try_fold_with(folder)?, }) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.literal.visit_with(visitor)?; - self.user_ty.visit_with(visitor) - } } impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { @@ -365,10 +226,6 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_mir_const(self) } - - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - visitor.visit_mir_const(*self) - } } impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> { @@ -381,11 +238,4 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> { ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)), } } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - match *self { - ConstantKind::Ty(c) => c.visit_with(visitor), - ConstantKind::Val(_, t) => t.visit_with(visitor), - } - } } diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs new file mode 100644 index 0000000000000..6a0801cb0dd25 --- /dev/null +++ b/compiler/rustc_middle/src/mir/type_visitable.rs @@ -0,0 +1,190 @@ +//! `TypeVisitable` implementations for MIR types + +use super::*; +use crate::ty; + +impl<'tcx> TypeVisitable<'tcx> for Terminator<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + use crate::mir::TerminatorKind::*; + + match self.kind { + SwitchInt { ref discr, switch_ty, .. } => { + discr.visit_with(visitor)?; + switch_ty.visit_with(visitor) + } + Drop { ref place, .. } => place.visit_with(visitor), + DropAndReplace { ref place, ref value, .. } => { + place.visit_with(visitor)?; + value.visit_with(visitor) + } + Yield { ref value, .. } => value.visit_with(visitor), + Call { ref func, ref args, ref destination, .. } => { + destination.visit_with(visitor)?; + func.visit_with(visitor)?; + args.visit_with(visitor) + } + Assert { ref cond, ref msg, .. } => { + cond.visit_with(visitor)?; + use AssertKind::*; + match msg { + BoundsCheck { ref len, ref index } => { + len.visit_with(visitor)?; + index.visit_with(visitor) + } + Overflow(_, l, r) => { + l.visit_with(visitor)?; + r.visit_with(visitor) + } + OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { + op.visit_with(visitor) + } + ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE, + } + } + InlineAsm { ref operands, .. } => operands.visit_with(visitor), + Goto { .. } + | Resume + | Abort + | Return + | GeneratorDrop + | Unreachable + | FalseEdge { .. } + | FalseUnwind { .. } => ControlFlow::CONTINUE, + } + } +} + +impl<'tcx> TypeVisitable<'tcx> for GeneratorKind { + fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { + ControlFlow::CONTINUE + } +} + +impl<'tcx> TypeVisitable<'tcx> for Place<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.local.visit_with(visitor)?; + self.projection.visit_with(visitor) + } +} + +impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.iter().try_for_each(|t| t.visit_with(visitor)) + } +} + +impl<'tcx> TypeVisitable<'tcx> for Rvalue<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + use crate::mir::Rvalue::*; + match *self { + Use(ref op) => op.visit_with(visitor), + CopyForDeref(ref place) => { + let op = &Operand::Copy(*place); + op.visit_with(visitor) + } + Repeat(ref op, _) => op.visit_with(visitor), + ThreadLocalRef(did) => did.visit_with(visitor), + Ref(region, _, ref place) => { + region.visit_with(visitor)?; + place.visit_with(visitor) + } + AddressOf(_, ref place) => place.visit_with(visitor), + Len(ref place) => place.visit_with(visitor), + Cast(_, ref op, ty) => { + op.visit_with(visitor)?; + ty.visit_with(visitor) + } + BinaryOp(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (ref rhs, ref lhs)) => { + rhs.visit_with(visitor)?; + lhs.visit_with(visitor) + } + UnaryOp(_, ref val) => val.visit_with(visitor), + Discriminant(ref place) => place.visit_with(visitor), + NullaryOp(_, ty) => ty.visit_with(visitor), + Aggregate(ref kind, ref fields) => { + match **kind { + AggregateKind::Array(ty) => { + ty.visit_with(visitor)?; + } + AggregateKind::Tuple => {} + AggregateKind::Adt(_, _, substs, user_ty, _) => { + substs.visit_with(visitor)?; + user_ty.visit_with(visitor)?; + } + AggregateKind::Closure(_, substs) => { + substs.visit_with(visitor)?; + } + AggregateKind::Generator(_, substs, _) => { + substs.visit_with(visitor)?; + } + } + fields.visit_with(visitor) + } + ShallowInitBox(ref op, ty) => { + op.visit_with(visitor)?; + ty.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeVisitable<'tcx> for Operand<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match *self { + Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), + Operand::Constant(ref c) => c.visit_with(visitor), + } + } +} + +impl<'tcx> TypeVisitable<'tcx> for PlaceElem<'tcx> { + fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> { + use crate::mir::ProjectionElem::*; + + match self { + Field(_, ty) => ty.visit_with(visitor), + Index(v) => v.visit_with(visitor), + _ => ControlFlow::CONTINUE, + } + } +} + +impl<'tcx> TypeVisitable<'tcx> for Field { + fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { + ControlFlow::CONTINUE + } +} + +impl<'tcx> TypeVisitable<'tcx> for GeneratorSavedLocal { + fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { + ControlFlow::CONTINUE + } +} + +impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { + ControlFlow::CONTINUE + } +} + +impl<'tcx> TypeVisitable<'tcx> for Constant<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.literal.visit_with(visitor)?; + self.user_ty.visit_with(visitor) + } +} + +impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + visitor.visit_mir_const(*self) + } +} + +impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match *self { + ConstantKind::Ty(c) => c.visit_with(visitor), + ConstantKind::Val(_, t) => t.visit_with(visitor), + } + } +} diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 5ce92d127f3db..e5599fb15ad31 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -30,9 +30,11 @@ //! For example, the `super_basic_block_data` method begins like this: //! //! ```ignore (pseudo-rust) -//! fn super_basic_block_data(&mut self, -//! block: BasicBlock, -//! data: & $($mutability)? BasicBlockData<'tcx>) { +//! fn super_basic_block_data( +//! &mut self, +//! block: BasicBlock, +//! data: & $($mutability)? BasicBlockData<'tcx> +//! ) { //! let BasicBlockData { //! statements, //! terminator, @@ -78,106 +80,135 @@ macro_rules! make_mir_visitor { self.super_body(body); } - fn visit_basic_block_data(&mut self, - block: BasicBlock, - data: & $($mutability)? BasicBlockData<'tcx>) { + fn visit_basic_block_data( + &mut self, + block: BasicBlock, + data: & $($mutability)? BasicBlockData<'tcx>, + ) { self.super_basic_block_data(block, data); } - fn visit_source_scope_data(&mut self, - scope_data: & $($mutability)? SourceScopeData<'tcx>) { + fn visit_source_scope_data( + &mut self, + scope_data: & $($mutability)? SourceScopeData<'tcx>, + ) { self.super_source_scope_data(scope_data); } - fn visit_statement(&mut self, - statement: & $($mutability)? Statement<'tcx>, - location: Location) { + fn visit_statement( + &mut self, + statement: & $($mutability)? Statement<'tcx>, + location: Location, + ) { self.super_statement(statement, location); } - fn visit_assign(&mut self, - place: & $($mutability)? Place<'tcx>, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { + fn visit_assign( + &mut self, + place: & $($mutability)? Place<'tcx>, + rvalue: & $($mutability)? Rvalue<'tcx>, + location: Location, + ) { self.super_assign(place, rvalue, location); } - fn visit_terminator(&mut self, - terminator: & $($mutability)? Terminator<'tcx>, - location: Location) { + fn visit_terminator( + &mut self, + terminator: & $($mutability)? Terminator<'tcx>, + location: Location, + ) { self.super_terminator(terminator, location); } - fn visit_assert_message(&mut self, - msg: & $($mutability)? AssertMessage<'tcx>, - location: Location) { + fn visit_assert_message( + &mut self, + msg: & $($mutability)? AssertMessage<'tcx>, + location: Location, + ) { self.super_assert_message(msg, location); } - fn visit_rvalue(&mut self, - rvalue: & $($mutability)? Rvalue<'tcx>, - location: Location) { + fn visit_rvalue( + &mut self, + rvalue: & $($mutability)? Rvalue<'tcx>, + location: Location, + ) { self.super_rvalue(rvalue, location); } - fn visit_operand(&mut self, - operand: & $($mutability)? Operand<'tcx>, - location: Location) { + fn visit_operand( + &mut self, + operand: & $($mutability)? Operand<'tcx>, + location: Location, + ) { self.super_operand(operand, location); } - fn visit_ascribe_user_ty(&mut self, - place: & $($mutability)? Place<'tcx>, - variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection, - location: Location) { + fn visit_ascribe_user_ty( + &mut self, + place: & $($mutability)? Place<'tcx>, + variance: $(& $mutability)? ty::Variance, + user_ty: & $($mutability)? UserTypeProjection, + location: Location, + ) { self.super_ascribe_user_ty(place, variance, user_ty, location); } - fn visit_coverage(&mut self, - coverage: & $($mutability)? Coverage, - location: Location) { + fn visit_coverage( + &mut self, + coverage: & $($mutability)? Coverage, + location: Location, + ) { self.super_coverage(coverage, location); } - fn visit_retag(&mut self, - kind: & $($mutability)? RetagKind, - place: & $($mutability)? Place<'tcx>, - location: Location) { + fn visit_retag( + &mut self, + kind: $(& $mutability)? RetagKind, + place: & $($mutability)? Place<'tcx>, + location: Location, + ) { self.super_retag(kind, place, location); } - fn visit_place(&mut self, - place: & $($mutability)? Place<'tcx>, - context: PlaceContext, - location: Location) { + fn visit_place( + &mut self, + place: & $($mutability)? Place<'tcx>, + context: PlaceContext, + location: Location, + ) { self.super_place(place, context, location); } visit_place_fns!($($mutability)?); - fn visit_constant(&mut self, - constant: & $($mutability)? Constant<'tcx>, - location: Location) { + fn visit_constant( + &mut self, + constant: & $($mutability)? Constant<'tcx>, + location: Location, + ) { self.super_constant(constant, location); } - // The macro results in a false positive of sorts, where &mut Span - // is fine, but &Span is not; just allow the lint. - #[allow(rustc::pass_by_value)] - fn visit_span(&mut self, - span: & $($mutability)? Span) { + fn visit_span( + &mut self, + span: $(& $mutability)? Span, + ) { self.super_span(span); } - fn visit_source_info(&mut self, - source_info: & $($mutability)? SourceInfo) { + fn visit_source_info( + &mut self, + source_info: & $($mutability)? SourceInfo, + ) { self.super_source_info(source_info); } - fn visit_ty(&mut self, - ty: $(& $mutability)? Ty<'tcx>, - _: TyContext) { + fn visit_ty( + &mut self, + ty: $(& $mutability)? Ty<'tcx>, + _: TyContext, + ) { self.super_ty(ty); } @@ -196,45 +227,56 @@ macro_rules! make_mir_visitor { self.super_user_type_annotation(index, ty); } - fn visit_region(&mut self, - region: $(& $mutability)? ty::Region<'tcx>, - _: Location) { + fn visit_region( + &mut self, + region: $(& $mutability)? ty::Region<'tcx>, + _: Location, + ) { self.super_region(region); } - fn visit_const(&mut self, - constant: $(& $mutability)? ty::Const<'tcx>, - _: Location) { + fn visit_const( + &mut self, + constant: $(& $mutability)? ty::Const<'tcx>, + _: Location, + ) { self.super_const(constant); } - fn visit_substs(&mut self, - substs: & $($mutability)? SubstsRef<'tcx>, - _: Location) { + fn visit_substs( + &mut self, + substs: & $($mutability)? SubstsRef<'tcx>, + _: Location, + ) { self.super_substs(substs); } - fn visit_local_decl(&mut self, - local: Local, - local_decl: & $($mutability)? LocalDecl<'tcx>) { + fn visit_local_decl( + &mut self, + local: Local, + local_decl: & $($mutability)? LocalDecl<'tcx>, + ) { self.super_local_decl(local, local_decl); } - fn visit_var_debug_info(&mut self, - var_debug_info: & $($mutability)* VarDebugInfo<'tcx>) { + fn visit_var_debug_info( + &mut self, + var_debug_info: & $($mutability)* VarDebugInfo<'tcx>, + ) { self.super_var_debug_info(var_debug_info); } - #[allow(rustc::pass_by_value)] - fn visit_local(&mut self, - _local: & $($mutability)? Local, - _context: PlaceContext, - _location: Location) { - } + fn visit_local( + &mut self, + _local: $(& $mutability)? Local, + _context: PlaceContext, + _location: Location, + ) {} - #[allow(rustc::pass_by_value)] - fn visit_source_scope(&mut self, - scope: & $($mutability)? SourceScope) { + fn visit_source_scope( + &mut self, + scope: $(& $mutability)? SourceScope, + ) { self.super_source_scope(scope); } @@ -296,7 +338,7 @@ macro_rules! make_mir_visitor { self.visit_var_debug_info(var_debug_info); } - self.visit_span(&$($mutability)? body.span); + self.visit_span($(& $mutability)? body.span); for const_ in &$($mutability)? body.required_consts { let location = START_BLOCK.start_location(); @@ -338,14 +380,14 @@ macro_rules! make_mir_visitor { local_data: _, } = scope_data; - self.visit_span(span); + self.visit_span($(& $mutability)? *span); if let Some(parent_scope) = parent_scope { - self.visit_source_scope(parent_scope); + self.visit_source_scope($(& $mutability)? *parent_scope); } if let Some((callee, callsite_span)) = inlined { let location = START_BLOCK.start_location(); - self.visit_span(callsite_span); + self.visit_span($(& $mutability)? *callsite_span); let ty::Instance { def: callee_def, substs: callee_substs } = callee; match callee_def { @@ -368,7 +410,7 @@ macro_rules! make_mir_visitor { self.visit_substs(callee_substs, location); } if let Some(inlined_parent_scope) = inlined_parent_scope { - self.visit_source_scope(inlined_parent_scope); + self.visit_source_scope($(& $mutability)? *inlined_parent_scope); } } @@ -383,7 +425,7 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); match kind { StatementKind::Assign( - box(ref $($mutability)? place, ref $($mutability)? rvalue) + box (place, rvalue) ) => { self.visit_assign(place, rvalue, location); } @@ -410,26 +452,26 @@ macro_rules! make_mir_visitor { } StatementKind::StorageLive(local) => { self.visit_local( - local, + $(& $mutability)? *local, PlaceContext::NonUse(NonUseContext::StorageLive), location ); } StatementKind::StorageDead(local) => { self.visit_local( - local, + $(& $mutability)? *local, PlaceContext::NonUse(NonUseContext::StorageDead), location ); } StatementKind::Retag(kind, place) => { - self.visit_retag(kind, place, location); + self.visit_retag($(& $mutability)? *kind, place, location); } StatementKind::AscribeUserType( - box(ref $($mutability)? place, ref $($mutability)? user_ty), + box (place, user_ty), variance ) => { - self.visit_ascribe_user_ty(place, variance, user_ty, location); + self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location); } StatementKind::Coverage(coverage) => { self.visit_coverage( @@ -438,9 +480,9 @@ macro_rules! make_mir_visitor { ) } StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{ - ref $($mutability)? src, - ref $($mutability)? dst, - ref $($mutability)? count, + src, + dst, + count, }) => { self.visit_operand(src, location); self.visit_operand(dst, location); @@ -475,15 +517,14 @@ macro_rules! make_mir_visitor { TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { .. } | - TerminatorKind::FalseUnwind { .. } => { - } + TerminatorKind::FalseUnwind { .. } => {} TerminatorKind::Return => { // `return` logically moves from the return place `_0`. Note that the place // cannot be changed by any visitor, though. let $($mutability)? local = RETURN_PLACE; self.visit_local( - & $($mutability)? local, + $(& $mutability)? local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), location, ); @@ -670,6 +711,13 @@ macro_rules! make_mir_visitor { }; self.visit_place(path, ctx, location); } + Rvalue::CopyForDeref(place) => { + self.visit_place( + place, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), + location + ); + } Rvalue::AddressOf(m, path) => { let ctx = match m { @@ -788,7 +836,7 @@ macro_rules! make_mir_visitor { fn super_ascribe_user_ty(&mut self, place: & $($mutability)? Place<'tcx>, - _variance: & $($mutability)? ty::Variance, + _variance: $(& $mutability)? ty::Variance, user_ty: & $($mutability)? UserTypeProjection, location: Location) { self.visit_place( @@ -805,7 +853,7 @@ macro_rules! make_mir_visitor { } fn super_retag(&mut self, - _kind: & $($mutability)? RetagKind, + _kind: $(& $mutability)? RetagKind, place: & $($mutability)? Place<'tcx>, location: Location) { self.visit_place( @@ -840,8 +888,10 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); } - fn super_var_debug_info(&mut self, - var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) { + fn super_var_debug_info( + &mut self, + var_debug_info: & $($mutability)? VarDebugInfo<'tcx> + ) { let VarDebugInfo { name: _, source_info, @@ -861,21 +911,23 @@ macro_rules! make_mir_visitor { } } - #[allow(rustc::pass_by_value)] - fn super_source_scope(&mut self, - _scope: & $($mutability)? SourceScope) { - } + fn super_source_scope( + &mut self, + _scope: $(& $mutability)? SourceScope + ) {} - fn super_constant(&mut self, - constant: & $($mutability)? Constant<'tcx>, - location: Location) { + fn super_constant( + &mut self, + constant: & $($mutability)? Constant<'tcx>, + location: Location + ) { let Constant { span, user_ty, literal, } = constant; - self.visit_span(span); + self.visit_span($(& $mutability)? *span); drop(user_ty); // no visit method for this match literal { ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location), @@ -883,10 +935,7 @@ macro_rules! make_mir_visitor { } } - // The macro results in a false positive of sorts, where &mut Span - // is fine, but &Span is not; just allow the lint. - #[allow(rustc::pass_by_value)] - fn super_span(&mut self, _span: & $($mutability)? Span) { + fn super_span(&mut self, _span: $(& $mutability)? Span) { } fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) { @@ -895,8 +944,8 @@ macro_rules! make_mir_visitor { scope, } = source_info; - self.visit_span(span); - self.visit_source_scope(scope); + self.visit_span($(& $mutability)? *span); + self.visit_source_scope($(& $mutability)? *scope); } fn super_user_type_projection( @@ -910,7 +959,7 @@ macro_rules! make_mir_visitor { _index: UserTypeAnnotationIndex, ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, ) { - self.visit_span(& $($mutability)? ty.span); + self.visit_span($(& $mutability)? ty.span); self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); } @@ -1015,6 +1064,11 @@ macro_rules! visit_place_fns { self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } } + PlaceElem::OpaqueCast(ty) => { + let mut new_ty = ty; + self.visit_ty(&mut new_ty, TyContext::Location(location)); + if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } + } PlaceElem::Deref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } @@ -1058,7 +1112,7 @@ macro_rules! visit_place_fns { } } - self.visit_local(&place.local, context, location); + self.visit_local(place.local, context, location); self.visit_projection(place.as_ref(), context, location); } @@ -1069,11 +1123,9 @@ macro_rules! visit_place_fns { context: PlaceContext, location: Location, ) { - // FIXME: Use PlaceRef::iter_projections, once that exists. - let mut cursor = place_ref.projection; - while let &[ref proj_base @ .., elem] = cursor { - cursor = proj_base; - self.visit_projection_elem(place_ref.local, cursor, elem, context, location); + for (base, elem) in place_ref.iter_projections().rev() { + let base_proj = base.projection; + self.visit_projection_elem(place_ref.local, base_proj, elem, context, location); } } @@ -1086,12 +1138,12 @@ macro_rules! visit_place_fns { location: Location, ) { match elem { - ProjectionElem::Field(_field, ty) => { + ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => { self.visit_ty(ty, TyContext::Location(location)); } ProjectionElem::Index(local) => { self.visit_local( - &local, + local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ca2c03cb614bb..bdae7e5fcd6b1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -26,6 +26,12 @@ rustc_queries! { desc { "get the resolver outputs" } } + query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> { + eval_always + no_hash + desc { "get the resolver for lowering" } + } + /// Return the span for a definition. /// Contrary to `def_span` below, this query returns the full absolute span of the definition. /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside @@ -40,7 +46,8 @@ rustc_queries! { /// This is because the `hir_crate` query gives you access to all other items. /// To avoid this fate, do not call `tcx.hir().krate()`; instead, /// prefer wrappers like `tcx.visit_all_items_in_krate()`. - query hir_crate(key: ()) -> &'tcx Crate<'tcx> { + query hir_crate(key: ()) -> Crate<'tcx> { + storage(ArenaCacheSelector<'tcx>) eval_always desc { "get the crate HIR" } } @@ -344,7 +351,7 @@ rustc_queries! { /// Try to build an abstract representation of the given constant. query thir_abstract_const( key: DefId - ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> { + ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } @@ -353,7 +360,7 @@ rustc_queries! { /// Try to build an abstract representation of the given constant. query thir_abstract_const_of_const_arg( key: (LocalDefId, DefId) - ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> { + ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> { desc { |tcx| "building an abstract representation for the const argument {}", @@ -826,6 +833,10 @@ rustc_queries! { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } } + query check_mod_type_wf(key: LocalDefId) -> () { + desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } + } + query collect_mod_item_types(key: LocalDefId) -> () { desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) } } @@ -906,9 +917,10 @@ rustc_queries! { /// Checks whether all impls in the crate pass the overlap check, returning /// which impls fail it. If all impls are correct, the returned slice is empty. - query orphan_check_crate(_: ()) -> &'tcx [LocalDefId] { - desc { - "checking whether the immpl in the this crate follow the orphan rules", + query orphan_check_impl(key: LocalDefId) -> Result<(), ErrorGuaranteed> { + desc { |tcx| + "checking whether impl `{}` follows the orphan rules", + tcx.def_path_str(key.to_def_id()), } } @@ -973,11 +985,9 @@ rustc_queries! { desc { "converting type-level constant value to mir constant value"} } - /// Destructure a constant ADT or array into its variant index and its - /// field values or return `None` if constant is invalid. - /// - /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid. - query try_destructure_const(key: ty::Const<'tcx>) -> Option<ty::DestructuredConst<'tcx>> { + /// Destructures array, ADT or tuple constants into the constants + /// of their fields. + query destructure_const(key: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> { desc { "destructuring type level constant"} } @@ -1353,9 +1363,13 @@ rustc_queries! { desc { "query a crate is `#![profiler_runtime]`" } separate_provide_extern } - query panic_strategy(_: CrateNum) -> PanicStrategy { + query has_ffi_unwind_calls(key: LocalDefId) -> bool { + desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } + } + query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> { fatal_cycle - desc { "query a crate's configured panic strategy" } + desc { "query a crate's required panic strategy" } separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { @@ -1398,13 +1412,7 @@ rustc_queries! { separate_provide_extern } - query check_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } - } - query check_trait_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } - } - query check_impl_item_well_formed(key: LocalDefId) -> () { + query check_well_formed(key: LocalDefId) -> () { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } } @@ -1572,7 +1580,7 @@ rustc_queries! { Option<&'tcx FxHashMap<ItemLocalId, Region>> { desc { "looking up a named region" } } - query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxHashSet<LocalDefId>> { + query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> { desc { "testing if a region is late bound" } } /// For a given item (like a struct), gets the default lifetimes to be used @@ -1824,7 +1832,8 @@ rustc_queries! { remap_env_constness } - /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. + /// Do not call this query directly: + /// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead. query dropck_outlives( goal: CanonicalTyGoal<'tcx> ) -> Result< diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 120d09ee35382..36db8d04918b0 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -30,7 +30,6 @@ use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; -pub mod abstract_const; pub mod visit; newtype_index! { @@ -182,6 +181,9 @@ pub enum StmtKind<'tcx> { /// `let pat: ty = <INIT>` initializer: Option<ExprId>, + /// `let pat: ty = <INIT> else { <ELSE> } + else_block: Option<Block>, + /// The lint level for this `let` statement. lint_level: LintLevel, }, @@ -191,18 +193,8 @@ pub enum StmtKind<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Expr<'_>, 104); -#[derive( - Clone, - Debug, - Copy, - PartialEq, - Eq, - Hash, - HashStable, - TyEncodable, - TyDecodable, - TypeFoldable -)] +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct LocalVarId(pub hir::HirId); /// A THIR expression. @@ -429,6 +421,10 @@ pub enum ExprKind<'tcx> { lit: ty::ScalarInt, user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, }, + /// A literal of a ZST type. + ZstLiteral { + user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + }, /// Associated constants and named constants NamedConst { def_id: DefId, @@ -464,12 +460,6 @@ pub enum ExprKind<'tcx> { }, } -impl<'tcx> ExprKind<'tcx> { - pub fn zero_sized_literal(user_ty: Option<Canonical<'tcx, UserType<'tcx>>>) -> Self { - ExprKind::NonHirLiteral { lit: ty::ScalarInt::ZST, user_ty } - } -} - /// Represents the association of a field identifier and an expression. /// /// This is used in struct constructors. diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs deleted file mode 100644 index e02ed414574b4..0000000000000 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! A subset of a mir body used for const evaluatability checking. -use crate::mir; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_errors::ErrorGuaranteed; - -rustc_index::newtype_index! { - /// An index into an `AbstractConst`. - pub struct NodeId { - derive [HashStable] - DEBUG_FORMAT = "n{}", - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum CastKind { - /// thir::ExprKind::As - As, - /// thir::ExprKind::Use - Use, -} - -/// A node of an `AbstractConst`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum Node<'tcx> { - Leaf(ty::Const<'tcx>), - Binop(mir::BinOp, NodeId, NodeId), - UnaryOp(mir::UnOp, NodeId), - FunctionCall(NodeId, &'tcx [NodeId]), - Cast(CastKind, NodeId, Ty<'tcx>), -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -pub enum NotConstEvaluatable { - Error(ErrorGuaranteed), - MentionsInfer, - MentionsParam, -} - -impl From<ErrorGuaranteed> for NotConstEvaluatable { - fn from(e: ErrorGuaranteed) -> NotConstEvaluatable { - NotConstEvaluatable::Error(e) - } -} - -TrivialTypeFoldableAndLiftImpls! { - NotConstEvaluatable, -} - -impl<'tcx> TyCtxt<'tcx> { - #[inline] - pub fn thir_abstract_const_opt_const_arg( - self, - def: ty::WithOptConstParam<rustc_hir::def_id::DefId>, - ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> { - if let Some((did, param_did)) = def.as_const_arg() { - self.thir_abstract_const_of_const_arg((did, param_did)) - } else { - self.thir_abstract_const(def.did) - } - } -} diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 8c8ebb0a6b87a..97249fdd17563 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -129,6 +129,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} Literal { lit: _, neg: _ } => {} NonHirLiteral { lit: _, user_ty: _ } => {} + ZstLiteral { user_ty: _ } => {} NamedConst { def_id: _, substs: _, user_ty: _ } => {} ConstParam { param: _, def_id: _ } => {} StaticRef { alloc_id: _, ty: _, def_id: _ } => {} @@ -166,11 +167,15 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm init_scope: _, ref pattern, lint_level: _, + else_block, } => { if let Some(init) = initializer { visitor.visit_expr(&visitor.thir()[*init]); } visitor.visit_pat(pattern); + if let Some(block) = else_block { + visitor.visit_block(block) + } } } } diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs index 70abdb9ab4cd7..6d4af8bea6281 100644 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -390,7 +390,7 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { } /// A chalk environment and goal. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct ChalkEnvironmentAndGoal<'tcx> { pub environment: &'tcx ty::List<ty::Predicate<'tcx>>, pub goal: ty::Predicate<'tcx>, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 5258d37a14c91..75559d4f8b843 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -10,9 +10,9 @@ mod structural_impls; pub mod util; use crate::infer::canonical::Canonical; -use crate::thir::abstract_const::NotConstEvaluatable; +use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; -use crate::ty::{self, AdtKind, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; @@ -139,13 +139,8 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() } } - pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { + pub fn span(&self) -> Span { match *self.code() { - ObligationCauseCode::CompareImplMethodObligation { .. } - | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType => { - tcx.sess.source_map().guess_head_span(self.span) - } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { arm_span, .. @@ -253,7 +248,7 @@ pub enum ObligationCauseCode<'tcx> { ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Object type */ Ty<'tcx>), + ObjectCastObligation(/* Concrete type */ Ty<'tcx>, /* Object type */ Ty<'tcx>), /// Obligation incurred due to a coercion. Coercion { @@ -406,7 +401,7 @@ pub enum ObligationCauseCode<'tcx> { QuestionMark, /// Well-formed checking. If a `WellFormedLoc` is provided, - /// then it will be used to eprform HIR-based wf checking + /// then it will be used to perform HIR-based wf checking /// after an error occurs, in order to generate a more precise error span. /// This is purely for diagnostic purposes - it is always /// correct to use `MiscObligation` instead, or to specify @@ -419,6 +414,7 @@ pub enum ObligationCauseCode<'tcx> { BinOp { rhs_span: Option<Span>, is_lit: bool, + output_pred: Option<Predicate<'tcx>>, }, } @@ -523,7 +519,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_code: InternedObligationCauseCode<'tcx>, } -#[derive(Clone, Debug, TypeFoldable, Lift)] +#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub enum SelectionError<'tcx> { /// The trait is not implemented. Unimplemented, @@ -592,7 +588,8 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; /// ### The type parameter `N` /// /// See explanation on `ImplSourceUserDefinedData`. -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub enum ImplSource<'tcx, N> { /// ImplSource identifying a particular impl. UserDefined(ImplSourceUserDefinedData<'tcx, N>), @@ -753,14 +750,16 @@ impl<'tcx, N> ImplSource<'tcx, N> { /// is `Obligation`, as one might expect. During codegen, however, this /// is `()`, because codegen only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceUserDefinedData<'tcx, N> { pub impl_def_id: DefId, pub substs: SubstsRef<'tcx>, pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceGeneratorData<'tcx, N> { pub generator_def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -769,7 +768,8 @@ pub struct ImplSourceGeneratorData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceClosureData<'tcx, N> { pub closure_def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -778,13 +778,15 @@ pub struct ImplSourceClosureData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceAutoImplData<N> { pub trait_def_id: DefId, pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceTraitUpcastingData<'tcx, N> { /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, @@ -798,12 +800,14 @@ pub struct ImplSourceTraitUpcastingData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceBuiltinData<N> { pub nested: Vec<N>, } -#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceObjectData<'tcx, N> { /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, @@ -817,7 +821,8 @@ pub struct ImplSourceObjectData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceFnPointerData<'tcx, N> { pub fn_ty: Ty<'tcx>, pub nested: Vec<N>, @@ -830,12 +835,14 @@ pub struct ImplSourceDiscriminantKindData; #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub struct ImplSourcePointeeData; -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceConstDestructData<N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceTraitAliasData<'tcx, N> { pub alias_def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -863,7 +870,7 @@ pub enum ObjectSafetyViolation { impl ObjectSafetyViolation { pub fn error_msg(&self) -> Cow<'static, str> { - match *self { + match self { ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), ObjectSafetyViolation::SupertraitSelf(ref spans) => { if spans.iter().any(|sp| *sp != DUMMY_SP) { @@ -873,7 +880,7 @@ impl ObjectSafetyViolation { .into() } } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_, _, _), _) => { + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() } ObjectSafetyViolation::Method( @@ -897,9 +904,11 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { format!("method `{}` has generic type parameters", name).into() } - ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => { - format!("method `{}`'s `self` parameter cannot be dispatched on", name).into() - } + ObjectSafetyViolation::Method( + name, + MethodViolationCode::UndispatchableReceiver(_), + _, + ) => format!("method `{}`'s `self` parameter cannot be dispatched on", name).into(), ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { format!("it contains associated `const` `{}`", name).into() } @@ -911,51 +920,40 @@ impl ObjectSafetyViolation { } pub fn solution(&self, err: &mut Diagnostic) { - match *self { + match self { ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {} ObjectSafetyViolation::Method( name, - MethodViolationCode::StaticMethod(sugg, self_span, has_args), + MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), _, ) => { err.span_suggestion( - self_span, - &format!( + add_self_sugg.1, + format!( "consider turning `{}` into a method by giving it a `&self` argument", name ), - format!("&self{}", if has_args { ", " } else { "" }), + add_self_sugg.0.to_string(), + Applicability::MaybeIncorrect, + ); + err.span_suggestion( + make_sized_sugg.1, + format!( + "alternatively, consider constraining `{}` so it does not apply to \ + trait objects", + name + ), + make_sized_sugg.0.to_string(), Applicability::MaybeIncorrect, ); - match sugg { - Some((sugg, span)) => { - err.span_suggestion( - span, - &format!( - "alternatively, consider constraining `{}` so it does not apply to \ - trait objects", - name - ), - sugg, - Applicability::MaybeIncorrect, - ); - } - None => { - err.help(&format!( - "consider turning `{}` into a method by giving it a `&self` \ - argument or constraining it so it does not apply to trait objects", - name - )); - } - } } ObjectSafetyViolation::Method( name, - MethodViolationCode::UndispatchableReceiver, - span, + MethodViolationCode::UndispatchableReceiver(Some(span)), + _, ) => { err.span_suggestion( - span, + *span, &format!( "consider changing method `{}`'s `self` parameter to be `&self`", name @@ -991,13 +989,13 @@ impl ObjectSafetyViolation { } /// Reasons a method might not be object-safe. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum MethodViolationCode { /// e.g., `fn foo()` - StaticMethod(Option<(&'static str, Span)>, Span, bool /* has args */), + StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>), /// e.g., `fn foo(&self, x: Self)` - ReferencesSelfInput(usize), + ReferencesSelfInput(Option<Span>), /// e.g., `fn foo(&self) -> Self` ReferencesSelfOutput, @@ -1009,7 +1007,7 @@ pub enum MethodViolationCode { Generic, /// the method's receiver (`self` argument) can't be dispatched on - UndispatchableReceiver, + UndispatchableReceiver(Option<Span>), } /// These are the error cases for `codegen_fulfill_obligation`. diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index d43492c903cfe..937b166d484b3 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -24,7 +24,8 @@ pub mod type_op { use rustc_hir::def_id::DefId; use std::fmt; - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] + #[derive(TypeFoldable, TypeVisitable)] pub struct AscribeUserType<'tcx> { pub mir_ty: Ty<'tcx>, pub def_id: DefId, @@ -37,19 +38,22 @@ pub mod type_op { } } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] + #[derive(TypeFoldable, TypeVisitable)] pub struct Eq<'tcx> { pub a: Ty<'tcx>, pub b: Ty<'tcx>, } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] + #[derive(TypeFoldable, TypeVisitable)] pub struct Subtype<'tcx> { pub sub: Ty<'tcx>, pub sup: Ty<'tcx>, } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] + #[derive(TypeFoldable, TypeVisitable)] pub struct ProvePredicate<'tcx> { pub predicate: Predicate<'tcx>, } @@ -60,7 +64,8 @@ pub mod type_op { } } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] + #[derive(TypeFoldable, TypeVisitable)] pub struct Normalize<T> { pub value: T, } @@ -107,7 +112,7 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution { } } -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] +#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct DropckOutlivesResult<'tcx> { pub kinds: Vec<GenericArg<'tcx>>, pub overflows: Vec<Ty<'tcx>>, @@ -208,7 +213,7 @@ pub struct MethodAutoderefBadTy<'tcx> { } /// Result from the `normalize_projection_ty` query. -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] +#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct NormalizationResult<'tcx> { /// Result of normalization. pub normalized_ty: Ty<'tcx>, @@ -221,7 +226,7 @@ pub struct NormalizationResult<'tcx> { /// case they are called implied bounds). They are fed to the /// `OutlivesEnv` which in turn is supplied to the region checker and /// other parts of the inference system. -#[derive(Clone, Debug, TypeFoldable, Lift)] +#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)] pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index ffa70cddbd59c..0ca5a532b7542 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -103,7 +103,7 @@ pub type EvaluationCache<'tcx> = Cache< /// required for associated types to work in default impls, as the bounds /// are visible both as projection bounds and as where-clauses from the /// parameter environment. -#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)] +#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)] pub enum SelectionCandidate<'tcx> { BuiltinCandidate { /// `false` if there are no *further* obligations. @@ -176,6 +176,10 @@ pub enum EvaluationResult { EvaluatedToOk, /// Evaluation successful, but there were unevaluated region obligations. EvaluatedToOkModuloRegions, + /// Evaluation successful, but need to rerun because opaque types got + /// hidden types assigned without it being known whether the opaque types + /// are within their defining scope + EvaluatedToOkModuloOpaqueTypes, /// Evaluation is known to be ambiguous -- it *might* hold for some /// assignment of inference variables, but it might not. /// @@ -252,9 +256,11 @@ impl EvaluationResult { pub fn may_apply(self) -> bool { match self { - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { - true - } + EvaluatedToOkModuloOpaqueTypes + | EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToAmbig + | EvaluatedToUnknown => true, EvaluatedToErr | EvaluatedToRecur => false, } @@ -264,7 +270,11 @@ impl EvaluationResult { match self { EvaluatedToUnknown | EvaluatedToRecur => true, - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, + EvaluatedToOkModuloOpaqueTypes + | EvaluatedToOk + | EvaluatedToOkModuloRegions + | EvaluatedToAmbig + | EvaluatedToErr => false, } } } @@ -283,7 +293,7 @@ impl From<ErrorGuaranteed> for OverflowError { } } -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { OverflowError, } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index ce13825b01696..3c1d0061ae127 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -1,5 +1,5 @@ use crate::ty::fast_reject::SimplifiedType; -use crate::ty::fold::TypeFoldable; +use crate::ty::visit::TypeVisitable; use crate::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index ea706053231f8..8f1a1564fc8e8 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -129,7 +129,7 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> { /////////////////////////////////////////////////////////////////////////// // Lift implementations -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { super::IfExpressionCause, super::ImplSourceDiscriminantKindData, super::ImplSourcePointeeData, diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs new file mode 100644 index 0000000000000..bed809930da61 --- /dev/null +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -0,0 +1,194 @@ +//! A subset of a mir body used for const evaluatability checking. +use crate::mir; +use crate::ty::visit::TypeVisitable; +use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt}; +use rustc_errors::ErrorGuaranteed; +use rustc_hir::def_id::DefId; +use std::cmp; +use std::ops::ControlFlow; + +rustc_index::newtype_index! { + /// An index into an `AbstractConst`. + pub struct NodeId { + derive [HashStable] + DEBUG_FORMAT = "n{}", + } +} + +/// A tree representing an anonymous constant. +/// +/// This is only able to represent a subset of `MIR`, +/// and should not leak any information about desugarings. +#[derive(Debug, Clone, Copy)] +pub struct AbstractConst<'tcx> { + // FIXME: Consider adding something like `IndexSlice` + // and use this here. + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, +} + +impl<'tcx> AbstractConst<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + uv: ty::Unevaluated<'tcx, ()>, + ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> { + let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; + debug!("AbstractConst::new({:?}) = {:?}", uv, inner); + Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) })) + } + + pub fn from_const( + tcx: TyCtxt<'tcx>, + ct: ty::Const<'tcx>, + ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> { + match ct.kind() { + ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()), + ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported), + _ => Ok(None), + } + } + + #[inline] + pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { + AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs } + } + + #[inline] + pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { + let node = self.inner.last().copied().unwrap(); + match node { + Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)), + Node::Cast(kind, operand, ty) => { + Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs)) + } + // Don't perform substitution on the following as they can't directly contain generic params + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node, + } + } + + pub fn unify_failure_kind(self, tcx: TyCtxt<'tcx>) -> FailureKind { + let mut failure_kind = FailureKind::Concrete; + walk_abstract_const::<!, _>(tcx, self, |node| { + match node.root(tcx) { + Node::Leaf(leaf) => { + if leaf.has_infer_types_or_consts() { + failure_kind = FailureKind::MentionsInfer; + } else if leaf.has_param_types_or_consts() { + failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); + } + } + Node::Cast(_, _, ty) => { + if ty.has_infer_types_or_consts() { + failure_kind = FailureKind::MentionsInfer; + } else if ty.has_param_types_or_consts() { + failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); + } + } + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {} + } + ControlFlow::CONTINUE + }); + failure_kind + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum CastKind { + /// thir::ExprKind::As + As, + /// thir::ExprKind::Use + Use, +} + +/// A node of an `AbstractConst`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum Node<'tcx> { + Leaf(ty::Const<'tcx>), + Binop(mir::BinOp, NodeId, NodeId), + UnaryOp(mir::UnOp, NodeId), + FunctionCall(NodeId, &'tcx [NodeId]), + Cast(CastKind, NodeId, Ty<'tcx>), +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum NotConstEvaluatable { + Error(ErrorGuaranteed), + MentionsInfer, + MentionsParam, +} + +impl From<ErrorGuaranteed> for NotConstEvaluatable { + fn from(e: ErrorGuaranteed) -> NotConstEvaluatable { + NotConstEvaluatable::Error(e) + } +} + +TrivialTypeTraversalAndLiftImpls! { + NotConstEvaluatable, +} + +impl<'tcx> TyCtxt<'tcx> { + #[inline] + pub fn thir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam<DefId>, + ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> { + if let Some((did, param_did)) = def.as_const_arg() { + self.thir_abstract_const_of_const_arg((did, param_did)) + } else { + self.thir_abstract_const(def.did) + } + } +} + +#[instrument(skip(tcx, f), level = "debug")] +pub fn walk_abstract_const<'tcx, R, F>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + mut f: F, +) -> ControlFlow<R> +where + F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, +{ + #[instrument(skip(tcx, f), level = "debug")] + fn recurse<'tcx, R>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, + ) -> ControlFlow<R> { + f(ct)?; + let root = ct.root(tcx); + debug!(?root); + match root { + Node::Leaf(_) => ControlFlow::CONTINUE, + Node::Binop(_, l, r) => { + recurse(tcx, ct.subtree(l), f)?; + recurse(tcx, ct.subtree(r), f) + } + Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), + Node::FunctionCall(func, args) => { + recurse(tcx, ct.subtree(func), f)?; + args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) + } + Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), + } + } + + recurse(tcx, ct, &mut f) +} + +// We were unable to unify the abstract constant with +// a constant found in the caller bounds, there are +// now three possible cases here. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum FailureKind { + /// The abstract const still references an inference + /// variable, in this case we return `TooGeneric`. + MentionsInfer, + /// The abstract const references a generic parameter, + /// this means that we emit an error here. + MentionsParam, + /// The substs are concrete enough that we can simply + /// try and evaluate the given constant. + Concrete, +} diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index d9332f6896af6..d36cf2fe3f8d0 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -77,7 +77,7 @@ pub enum PointerCast { /// At some point, of course, `Box` should move out of the compiler, in which /// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` -> /// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, pub target: Ty<'tcx>, @@ -89,7 +89,7 @@ impl<'tcx> Adjustment<'tcx> { } } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum Adjust<'tcx> { /// Go from ! to any type. NeverToAny, @@ -107,7 +107,8 @@ pub enum Adjust<'tcx> { /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. /// The target type is `U` in both cases, with the region and mutability /// being those shared by both the receiver and the returned reference. -#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, @@ -165,7 +166,8 @@ impl From<AutoBorrowMutability> for hir::Mutability { } } -#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum AutoBorrow<'tcx> { /// Converts from T to &T. Ref(ty::Region<'tcx>, AutoBorrowMutability), diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index bf7cb610a9097..809406aff1878 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -52,6 +52,8 @@ bitflags! { /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; + /// Indicates whether the type is `UnsafeCell`. + const IS_UNSAFE_CELL = 1 << 9; } } @@ -165,22 +167,27 @@ impl<'a> HashStable<StableHashingContext<'a>> for AdtDefData { pub struct AdtDef<'tcx>(pub Interned<'tcx, AdtDefData>); impl<'tcx> AdtDef<'tcx> { + #[inline] pub fn did(self) -> DefId { self.0.0.did } + #[inline] pub fn variants(self) -> &'tcx IndexVec<VariantIdx, VariantDef> { &self.0.0.variants } + #[inline] pub fn variant(self, idx: VariantIdx) -> &'tcx VariantDef { &self.0.0.variants[idx] } + #[inline] pub fn flags(self) -> AdtFlags { self.0.0.flags } + #[inline] pub fn repr(self) -> ReprOptions { self.0.0.repr } @@ -242,6 +249,9 @@ impl AdtDefData { if Some(did) == tcx.lang_items().manually_drop() { flags |= AdtFlags::IS_MANUALLY_DROP; } + if Some(did) == tcx.lang_items().unsafe_cell_type() { + flags |= AdtFlags::IS_UNSAFE_CELL; + } AdtDefData { did, variants, flags, repr } } @@ -328,6 +338,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_BOX) } + /// Returns `true` if this is UnsafeCell<T>. + #[inline] + pub fn is_unsafe_cell(self) -> bool { + self.flags().contains(AdtFlags::IS_UNSAFE_CELL) + } + /// Returns `true` if this is `ManuallyDrop<T>`. #[inline] pub fn is_manually_drop(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 7ab192daf4b1d..3d65429f2e53c 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -8,7 +8,7 @@ pub enum BindingMode { BindByValue(Mutability), } -TrivialTypeFoldableAndLiftImpls! { BindingMode, } +TrivialTypeTraversalAndLiftImpls! { BindingMode, } impl BindingMode { pub fn convert(ba: BindingAnnotation) -> BindingMode { diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index 20a6af5f6c13b..c4b743dd46701 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -15,6 +15,12 @@ pub enum IntTy { Char, } +impl IntTy { + pub fn is_signed(self) -> bool { + matches!(self, Self::I) + } +} + // Valid types for the result of a non-coercion cast #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum CastTy<'tcx> { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index c88cac30a1927..8ead05122740e 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -18,18 +18,8 @@ use self::BorrowKind::*; // This represents accessing self in the closure structure pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1); -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - TyEncodable, - TyDecodable, - TypeFoldable, - HashStable -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct UpvarPath { pub hir_id: hir::HirId, } @@ -37,7 +27,8 @@ pub struct UpvarPath { /// Upvars do not get their own `NodeId`. Instead, we use the pair of /// the original var ID (that is, the root variable that is referenced /// by the upvar) and the ID of the closure expression. -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct UpvarId { pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, @@ -51,7 +42,8 @@ impl UpvarId { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum UpvarCapture { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -136,10 +128,19 @@ impl<'tcx> ClosureKind { None } } + + pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId { + match self { + ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(), + ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(), + ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(), + } + } } /// A composite describing a `Place` that is captured by a closure. -#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct CapturedPlace<'tcx> { /// The `Place` that is captured. pub place: HirPlace<'tcx>, @@ -284,7 +285,8 @@ pub fn is_ancestor_or_same_capture( /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct CaptureInfo { /// Expr Id pointing to use that resulted in selecting the current capture kind /// @@ -362,7 +364,8 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc curr_string } -#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)] +#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 9a363914dc332..e6ea3d8885376 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -12,7 +12,6 @@ use crate::mir::{ self, interpret::{AllocId, ConstAllocation}, }; -use crate::thir; use crate::traits; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtDef, Ty}; @@ -346,7 +345,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> } impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> - for [thir::abstract_const::Node<'tcx>] + for [ty::abstract_const::Node<'tcx>] { fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc_from_iter( @@ -356,7 +355,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> } impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> - for [thir::abstract_const::NodeId] + for [ty::abstract_const::NodeId] { fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc_from_iter( diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index bc52259b151d1..a4e7a12bba323 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -2,7 +2,7 @@ use crate::mir::interpret::LitToConstInput; use crate::mir::ConstantKind; use crate::ty::{ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, - TyCtxt, TypeFoldable, + TyCtxt, TypeVisitable, }; use rustc_data_structures::intern::Interned; use rustc_errors::ErrorGuaranteed; diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 51e51a63fd043..7436f0f6f4d33 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -4,6 +4,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::Size; use std::convert::{TryFrom, TryInto}; use std::fmt; +use std::num::NonZeroU8; use crate::ty::TyCtxt; @@ -123,7 +124,7 @@ pub struct ScalarInt { /// The first `size` bytes of `data` are the value. /// Do not try to read less or more bytes than that. The remaining bytes must be 0. data: u128, - size: u8, + size: NonZeroU8, } // Cannot derive these, as the derives take references to the fields, and we @@ -135,33 +136,31 @@ impl<CTX> crate::ty::HashStable<CTX> for ScalarInt { // Since `Self` is a packed struct, that would create a possibly unaligned reference, // which is UB. { self.data }.hash_stable(hcx, hasher); - self.size.hash_stable(hcx, hasher); + self.size.get().hash_stable(hcx, hasher); } } impl<S: Encoder> Encodable<S> for ScalarInt { fn encode(&self, s: &mut S) { s.emit_u128(self.data); - s.emit_u8(self.size); + s.emit_u8(self.size.get()); } } impl<D: Decoder> Decodable<D> for ScalarInt { fn decode(d: &mut D) -> ScalarInt { - ScalarInt { data: d.read_u128(), size: d.read_u8() } + ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() } } } impl ScalarInt { - pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 }; + pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() }; - pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 }; - - pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 }; + pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() }; #[inline] pub fn size(self) -> Size { - Size::from_bytes(self.size) + Size::from_bytes(self.size.get()) } /// Make sure the `data` fits in `size`. @@ -185,7 +184,7 @@ impl ScalarInt { #[inline] pub fn null(size: Size) -> Self { - Self { data: 0, size: size.bytes() as u8 } + Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() } } #[inline] @@ -197,7 +196,7 @@ impl ScalarInt { pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { let data = i.into(); if size.truncate(data) == data { - Some(Self { data, size: size.bytes() as u8 }) + Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() }) } else { None } @@ -209,7 +208,7 @@ impl ScalarInt { // `into` performed sign extension, we have to truncate let truncated = size.truncate(i as u128); if size.sign_extend(truncated) as i128 == i { - Some(Self { data: truncated, size: size.bytes() as u8 }) + Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() }) } else { None } @@ -225,7 +224,7 @@ impl ScalarInt { #[inline] pub fn to_bits(self, target_size: Size) -> Result<u128, Size> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); - if target_size.bytes() == u64::from(self.size) { + if target_size.bytes() == u64::from(self.size.get()) { self.check_data(); Ok(self.data) } else { @@ -339,7 +338,7 @@ macro_rules! from { fn from(u: $ty) -> Self { Self { data: u128::from(u), - size: std::mem::size_of::<$ty>() as u8, + size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(), } } } @@ -382,7 +381,7 @@ impl TryFrom<ScalarInt> for bool { impl From<char> for ScalarInt { #[inline] fn from(c: char) -> Self { - Self { data: c as u128, size: std::mem::size_of::<char>() as u8 } + Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() } } } @@ -409,7 +408,7 @@ impl From<Single> for ScalarInt { #[inline] fn from(f: Single) -> Self { // We trust apfloat to give us properly truncated data. - Self { data: f.to_bits(), size: 4 } + Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() } } } @@ -425,7 +424,7 @@ impl From<Double> for ScalarInt { #[inline] fn from(f: Double) -> Self { // We trust apfloat to give us properly truncated data. - Self { data: f.to_bits(), size: 8 } + Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() } } } @@ -439,19 +438,18 @@ impl TryFrom<ScalarInt> for Double { impl fmt::Debug for ScalarInt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.size == 0 { - self.check_data(); - write!(f, "<ZST>") - } else { - // Dispatch to LowerHex below. - write!(f, "0x{:x}", self) - } + // Dispatch to LowerHex below. + write!(f, "0x{:x}", self) } } impl fmt::LowerHex for ScalarInt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.check_data(); + if f.alternate() { + // Like regular ints, alternate flag adds leading `0x`. + write!(f, "0x")?; + } // Format as hex number wide enough to fit any value of the given `size`. // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". // Using a block `{self.data}` here to force a copy instead of using `self.data` @@ -459,7 +457,7 @@ impl fmt::LowerHex for ScalarInt { // would thus borrow `self.data`. Since `Self` // is a packed struct, that would create a possibly unaligned reference, which // is UB. - write!(f, "{:01$x}", { self.data }, self.size as usize * 2) + write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2) } } @@ -473,7 +471,7 @@ impl fmt::UpperHex for ScalarInt { // would thus borrow `self.data`. Since `Self` // is a packed struct, that would create a possibly unaligned reference, which // is UB. - write!(f, "{:01$X}", { self.data }, self.size as usize * 2) + write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2) } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 10d03065c795f..cb0137d2e5e09 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -4,7 +4,7 @@ use crate::mir::interpret::{AllocId, ConstValue, Scalar}; use crate::mir::Promoted; use crate::ty::subst::{InternalSubsts, SubstsRef}; use crate::ty::ParamEnv; -use crate::ty::{self, TyCtxt, TypeFoldable}; +use crate::ty::{self, TyCtxt, TypeVisitable}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c3df9a66fe718..a594dab2e20a3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -4,7 +4,7 @@ use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKind, DepKindStruct}; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; +use crate::lint::{struct_lint_level, LintLevelSource}; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::resolve_lifetime; use crate::middle::stability; @@ -32,12 +32,13 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; +use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal}; use rustc_data_structures::vec_map::VecMap; -use rustc_errors::{ErrorGuaranteed, MultiSpan}; +use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; +use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ @@ -390,7 +391,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> { /// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for /// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`. #[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)] -#[derive(TypeFoldable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct GeneratorInteriorTypeCause<'tcx> { /// Type of the captured binding. pub ty: Ty<'tcx>, @@ -871,7 +872,7 @@ rustc_index::newtype_index! { pub type CanonicalUserTypeAnnotations<'tcx> = IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>; -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalUserTypeAnnotation<'tcx> { pub user_ty: CanonicalUserType<'tcx>, pub span: Span, @@ -931,7 +932,7 @@ impl<'tcx> CanonicalUserType<'tcx> { /// from constants that are named via paths, like `Foo::<A>::new` and /// so forth. #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum UserType<'tcx> { Ty(Ty<'tcx>), @@ -1045,6 +1046,7 @@ impl<'tcx> Deref for TyCtxt<'tcx> { pub struct GlobalCtxt<'tcx> { pub arena: &'tcx WorkerLocal<Arena<'tcx>>, + pub hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, interners: CtxtInterners<'tcx>, @@ -1069,13 +1071,15 @@ pub struct GlobalCtxt<'tcx> { /// Common consts, pre-interned for your convenience. pub consts: CommonConsts<'tcx>, - definitions: rustc_hir::definitions::Definitions, + definitions: RwLock<Definitions>, cstore: Box<CrateStoreDyn>, /// Output of the resolver. pub(crate) untracked_resolutions: ty::ResolverOutputs, - - pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>, + untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>, + /// The entire crate as AST. This field serves as the input for the hir_crate query, + /// which lowers it from AST to HIR. It must not be read or used by anything else. + pub untracked_crate: Steal<Lrc<ast::Crate>>, /// This provides access to the incremental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by @@ -1233,10 +1237,12 @@ impl<'tcx> TyCtxt<'tcx> { s: &'tcx Session, lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, arena: &'tcx WorkerLocal<Arena<'tcx>>, - definitions: rustc_hir::definitions::Definitions, + hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, + definitions: Definitions, cstore: Box<CrateStoreDyn>, untracked_resolutions: ty::ResolverOutputs, - krate: &'tcx hir::Crate<'tcx>, + untracked_resolver_for_lowering: ty::ResolverAstLowering, + krate: Lrc<ast::Crate>, dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, @@ -1263,16 +1269,18 @@ impl<'tcx> TyCtxt<'tcx> { sess: s, lint_store, arena, + hir_arena, interners, dep_graph, - definitions, + definitions: RwLock::new(definitions), cstore, - untracked_resolutions, prof: s.prof.clone(), types: common_types, lifetimes: common_lifetimes, consts: common_consts, - untracked_crate: krate, + untracked_resolutions, + untracked_resolver_for_lowering: Steal::new(untracked_resolver_for_lowering), + untracked_crate: Steal::new(krate), on_disk_cache, queries, query_caches: query::QueryCaches::default(), @@ -1368,7 +1376,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. if let Some(id) = id.as_local() { - self.definitions.def_key(id) + self.definitions_untracked().def_key(id) } else { self.cstore.def_key(id) } @@ -1382,7 +1390,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_path(self, id: DefId) -> rustc_hir::definitions::DefPath { // Accessing the DefPath is ok, since it is part of DefPathHash. if let Some(id) = id.as_local() { - self.definitions.def_path(id) + self.definitions_untracked().def_path(id) } else { self.cstore.def_path(id) } @@ -1392,7 +1400,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash { // Accessing the DefPathHash is ok, it is incr. comp. stable. if let Some(def_id) = def_id.as_local() { - self.definitions.def_path_hash(def_id) + self.definitions_untracked().def_path_hash(def_id) } else { self.cstore.def_path_hash(def_id) } @@ -1429,7 +1437,7 @@ impl<'tcx> TyCtxt<'tcx> { // If this is a DefPathHash from the local crate, we can look up the // DefId in the tcx's `Definitions`. if stable_crate_id == self.sess.local_stable_crate_id() { - self.definitions.local_def_path_hash_to_def_id(hash, err).to_def_id() + self.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id() } else { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. @@ -1460,6 +1468,64 @@ impl<'tcx> TyCtxt<'tcx> { ) } + /// Create a new definition within the incr. comp. engine. + pub fn create_def(self, parent: LocalDefId, data: hir::definitions::DefPathData) -> LocalDefId { + // This function modifies `self.definitions` using a side-effect. + // We need to ensure that these side effects are re-run by the incr. comp. engine. + // Depending on the forever-red node will tell the graph that the calling query + // needs to be re-evaluated. + use rustc_query_system::dep_graph::DepNodeIndex; + self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); + + // The following call has the side effect of modifying the tables inside `definitions`. + // These very tables are relied on by the incr. comp. engine to decode DepNodes and to + // decode the on-disk cache. + // + // Any LocalDefId which is used within queries, either as key or result, either: + // - has been created before the construction of the TyCtxt; + // - has been created by this call to `create_def`. + // As a consequence, this LocalDefId is always re-created before it is needed by the incr. + // comp. engine itself. + // + // This call also writes to the value of `source_span` and `expn_that_defined` queries. + // This is fine because: + // - those queries are `eval_always` so we won't miss their result changing; + // - this write will have happened before these queries are called. + self.definitions.write().create_def(parent, data) + } + + pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx { + // Create a dependency to the crate to be sure we re-execute this when the amount of + // definitions change. + self.ensure().hir_crate(()); + // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // while iterating. If some query needs to add definitions, it should be `ensure`d above. + let definitions = self.definitions.leak(); + definitions.iter_local_def_id() + } + + pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { + // Create a dependency to the crate to be sure we reexcute this when the amount of + // definitions change. + self.ensure().hir_crate(()); + // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // while iterating. If some query needs to add definitions, it should be `ensure`d above. + let definitions = self.definitions.leak(); + definitions.def_path_table() + } + + pub fn def_path_hash_to_def_index_map( + self, + ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { + // Create a dependency to the crate to be sure we reexcute this when the amount of + // definitions change. + self.ensure().hir_crate(()); + // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // while iterating. If some query needs to add definitions, it should be `ensure`d above. + let definitions = self.definitions.leak(); + definitions.def_path_hash_to_def_index_map() + } + /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn { @@ -1468,8 +1534,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries - pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions { - &self.definitions + #[inline] + pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> { + self.definitions.read() } /// Note that this is *untracked* and should only be used within the query @@ -1480,23 +1547,18 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline(always)] - pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - StableHashingContext::new( - self.sess, - &self.definitions, - &*self.cstore, - &self.untracked_resolutions.source_span, - ) - } - - #[inline(always)] - pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> { - StableHashingContext::ignore_spans( + pub fn with_stable_hashing_context<R>( + self, + f: impl FnOnce(StableHashingContext<'_>) -> R, + ) -> R { + let definitions = self.definitions_untracked(); + let hcx = StableHashingContext::new( self.sess, - &self.definitions, + &*definitions, &*self.cstore, &self.untracked_resolutions.source_span, - ) + ); + f(hcx) } pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeResult { @@ -2304,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> { self.interners.intern_ty( st, self.sess, - &self.definitions, + &self.definitions.read(), &*self.cstore, // This is only used to create a stable hashing context. &self.untracked_resolutions.source_span, @@ -2787,6 +2849,18 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, + /// typically generated by `#[derive(LintDiagnostic)]`). + pub fn emit_spanned_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into<MultiSpan>, + decorator: impl for<'a> DecorateLint<'a, ()>, + ) { + self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag)) + } + pub fn struct_span_lint_hir( self, lint: &'static Lint, @@ -2798,6 +2872,17 @@ impl<'tcx> TyCtxt<'tcx> { struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate); } + /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically + /// generated by `#[derive(LintDiagnostic)]`). + pub fn emit_lint( + self, + lint: &'static Lint, + id: HirId, + decorator: impl for<'a> DecorateLint<'a, ()>, + ) { + self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag)) + } + pub fn struct_lint_node( self, lint: &'static Lint, @@ -2899,6 +2984,7 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { pub fn provide(providers: &mut ty::query::Providers) { providers.resolutions = |tcx, ()| &tcx.untracked_resolutions; + providers.resolver_for_lowering = |tcx, ()| &tcx.untracked_resolver_for_lowering; providers.module_reexports = |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]); providers.crate_name = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index a84b3c9373b13..25bc6dc616784 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,8 +3,8 @@ use std::ops::ControlFlow; use crate::ty::{ - fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, - PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor, + visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, + PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; @@ -87,7 +87,7 @@ pub trait IsSuggestable<'tcx> { impl<'tcx, T> IsSuggestable<'tcx> for T where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 6d7e60ecc31be..f39fa363a160e 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,5 +1,6 @@ use crate::mir; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use crate::ty::visit::TypeVisitable; use crate::ty::{self, Ty, TyCtxt, TypeFlags}; pub(super) fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 812dd2adc2ed7..49a518b101dd1 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -13,7 +13,7 @@ use rustc_target::spec::abi; use std::borrow::Cow; use std::fmt; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub struct ExpectedFound<T> { pub expected: T, pub found: T, @@ -30,7 +30,7 @@ impl<T> ExpectedFound<T> { } // Data structures used in type unification -#[derive(Clone, Debug, TypeFoldable)] +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub enum TypeError<'tcx> { Mismatch, ConstnessMismatch(ExpectedFound<ty::BoundConstness>), @@ -795,7 +795,7 @@ fn foo(&self) -> Self::T { String::new() } if item_def_id == proj_ty_item_def_id => { Some(( - self.sess.source_map().guess_head_span(self.def_span(item.def_id)), + self.def_span(item.def_id), format!("consider calling `{}`", self.def_path_str(item.def_id)), )) } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index a8145e6820cac..8d019a3bad8cc 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,6 +1,6 @@ use crate::mir::Mutability; use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_hir::def_id::DefId; use std::fmt::Debug; use std::hash::Hash; diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 31b8fa1ce956f..f8893ae29f58e 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,76 +1,60 @@ -//! A generalized traversal mechanism for complex data structures that contain -//! type information. +//! A folding traversal mechanism for complex data structures that contain type +//! information. //! -//! There are two types of traversal. -//! - Folding. This is a modifying traversal. It consumes the data structure, -//! producing a (possibly) modified version of it. Both fallible and -//! infallible versions are available. The name is potentially -//! confusing, because this traversal is more like `Iterator::map` than -//! `Iterator::fold`. -//! - Visiting. This is a read-only traversal of the data structure. +//! This is a modifying traversal. It consumes the data structure, producing a +//! (possibly) modified version of it. Both fallible and infallible versions are +//! available. The name is potentially confusing, because this traversal is more +//! like `Iterator::map` than `Iterator::fold`. //! -//! These traversals have limited flexibility. Only a small number of "types of +//! This traversal has limited flexibility. Only a small number of "types of //! interest" within the complex data structures can receive custom -//! modification (when folding) or custom visitation (when visiting). These are -//! the ones containing the most important type-related information, such as -//! `Ty`, `Predicate`, `Region`, and `Const`. +//! modification. These are the ones containing the most important type-related +//! information, such as `Ty`, `Predicate`, `Region`, and `Const`. //! -//! There are three traits involved in each traversal type. -//! - `TypeFoldable`. This is implemented once for many types. This includes -//! both: +//! There are three groups of traits involved in each traversal. +//! - `TypeFoldable`. This is implemented once for many types, including: //! - Types of interest, for which the the methods delegate to the -//! folder/visitor. +//! folder. //! - All other types, including generic containers like `Vec` and `Option`. -//! It defines a "skeleton" of how they should be traversed, for both -//! folding and visiting. +//! It defines a "skeleton" of how they should be folded. //! - `TypeSuperFoldable`. This is implemented only for each type of interest, -//! and defines the traversal "skeleton" for these types. -//! - `TypeFolder`/`FallibleTypeFolder` (for infallible/fallible folding -//! traversals) or `TypeVisitor` (for visiting traversals). One of these is -//! implemented for each folder/visitor. This defines how types of interest -//! are folded/visited. +//! and defines the folding "skeleton" for these types. +//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each +//! folder. This defines how types of interest are folded. //! -//! This means each traversal is a mixture of (a) generic traversal operations, -//! and (b) custom fold/visit operations that are specific to the -//! folder/visitor. +//! This means each fold is a mixture of (a) generic folding operations, and (b) +//! custom fold operations that are specific to the folder. //! - The `TypeFoldable` impls handle most of the traversal, and call into -//! `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a -//! type of interest. -//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may call into another -//! `TypeFoldable` impl, because some of the types of interest are recursive -//! and can contain other types of interest. -//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call into -//! a `TypeSuperFoldable` impl, because each folder/visitor might provide -//! custom handling only for some types of interest, or only for some -//! variants of each type of interest, and then use default traversal for the -//! remaining cases. +//! `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest. +//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable` +//! impl, because some of the types of interest are recursive and can contain +//! other types of interest. +//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable` +//! impl, because each folder might provide custom handling only for some types +//! of interest, or only for some variants of each type of interest, and then +//! use default traversal for the remaining cases. //! //! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U: -//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be visited like so: +//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so: //! ```text -//! s.visit_with(visitor) calls -//! - ty.visit_with(visitor) calls -//! - visitor.visit_ty(ty) may call -//! - ty.super_visit_with(visitor) -//! - u.visit_with(visitor) +//! s.fold_with(folder) calls +//! - ty.fold_with(folder) calls +//! - folder.fold_ty(ty) may call +//! - ty.super_fold_with(folder) +//! - u.fold_with(folder) //! ``` use crate::mir; -use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_errors::ErrorGuaranteed; +use crate::ty::{self, Binder, Ty, TyCtxt, TypeVisitable}; use rustc_hir::def_id::DefId; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sso::SsoHashSet; use std::collections::BTreeMap; -use std::fmt; -use std::ops::ControlFlow; -/// This trait is implemented for every type that can be folded/visited, +/// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. /// /// To implement this conveniently, use the derive macro located in /// `rustc_macros`. -pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { +pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> { /// The entry point for folding. To fold a value `t` with a folder `f` /// call: `t.try_fold_with(f)`. /// @@ -86,118 +70,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { /// A convenient alternative to `try_fold_with` for use with infallible /// folders. Do not override this method, to ensure coherence with /// `try_fold_with`. - fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self { + fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { self.try_fold_with(folder).into_ok() } - - /// The entry point for visiting. To visit a value `t` with a visitor `v` - /// call: `t.visit_with(v)`. - /// - /// For most types, this just traverses the value, calling `visit_with` on - /// each field/element. - /// - /// For types of interest (such as `Ty`), the implementation of this method - /// that calls a visitor method specifically for that type (such as - /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to - /// `TypeVisitor`. - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; - - /// Returns `true` if `self` has any late-bound regions that are either - /// bound by `binder` or bound by some binder outside of `binder`. - /// If `binder` is `ty::INNERMOST`, this indicates whether - /// there are any late-bound regions that appear free. - fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() - } - - /// Returns `true` if this `self` has any regions that escape `binder` (and - /// hence are not bound by it). - fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { - self.has_vars_bound_at_or_above(binder.shifted_in(1)) - } - - fn has_escaping_bound_vars(&self) -> bool { - self.has_vars_bound_at_or_above(ty::INNERMOST) - } - - #[instrument(level = "trace")] - fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) - } - fn has_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PROJECTION) - } - fn has_opaque_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) - } - fn references_error(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_ERROR) - } - fn error_reported(&self) -> Option<ErrorGuaranteed> { - if self.references_error() { - Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()) - } else { - None - } - } - fn has_param_types_or_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) - } - fn has_infer_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_INFER) - } - fn has_infer_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER) - } - fn has_infer_types_or_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER) - } - fn needs_infer(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_INFER) - } - fn has_placeholders(&self) -> bool { - self.has_type_flags( - TypeFlags::HAS_RE_PLACEHOLDER - | TypeFlags::HAS_TY_PLACEHOLDER - | TypeFlags::HAS_CT_PLACEHOLDER, - ) - } - fn needs_subst(&self) -> bool { - self.has_type_flags(TypeFlags::NEEDS_SUBST) - } - /// "Free" regions in this context means that it has any region - /// that is not (a) erased or (b) late-bound. - fn has_free_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - fn has_erased_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_ERASED) - } - - /// True if there are any un-erased free regions. - fn has_erasable_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) - } - - /// Indicates whether this value references only 'global' - /// generic parameters that are the same regardless of what fn we are - /// in. This is used for caching. - fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) - } - - /// True if there are any late-bound regions - fn has_late_bound_regions(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND) - } - - /// Indicates whether this value still has parameters/placeholders/inference variables - /// which could be replaced later, in a way that would change the results of `impl` - /// specialization. - fn still_further_specializable(&self) -> bool { - self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) - } } // This trait is implemented for types of interest. @@ -216,83 +91,51 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> { /// A convenient alternative to `try_super_fold_with` for use with /// infallible folders. Do not override this method, to ensure coherence /// with `try_super_fold_with`. - fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self { + fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { self.try_super_fold_with(folder).into_ok() } - - /// Provides a default visit for a type of interest. This should only be - /// called within `TypeVisitor` methods, when a non-custom traversal is - /// desired for the value of the type of interest passed to that method. - /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call - /// `ty.super_visit_with(self)`, but any other visiting should be done - /// with `xyz.visit_with(self)`. - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; } -/// This trait is implemented for every folding traversal. There is a fold -/// method defined for every type of interest. Each such method has a default -/// that does an "identity" fold. Implementations of these methods often fall -/// back to a `super_fold_with` method if the primary argument doesn't -/// satisfy a particular condition. +/// This trait is implemented for every infallible folding traversal. There is +/// a fold method defined for every type of interest. Each such method has a +/// default that does an "identity" fold. Implementations of these methods +/// often fall back to a `super_fold_with` method if the primary argument +/// doesn't satisfy a particular condition. /// -/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`] -/// associated type is something other than the default `!`) then -/// [`FallibleTypeFolder`] should be implemented manually. Otherwise, -/// a blanket implementation of [`FallibleTypeFolder`] will defer to +/// A blanket implementation of [`FallibleTypeFolder`] will defer to /// the infallible methods of this trait to ensure that the two APIs /// are coherent. -pub trait TypeFolder<'tcx>: Sized { - type Error = !; - +pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> where T: TypeFoldable<'tcx>, - Self: TypeFolder<'tcx, Error = !>, { t.super_fold_with(self) } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { t.super_fold_with(self) } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } - fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { c.super_fold_with(self) } - fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> { uv.super_fold_with(self) } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { p.super_fold_with(self) } - fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { bug!("most type folders should not be folding MIR datastructures: {:?}", c) } } @@ -304,7 +147,11 @@ pub trait TypeFolder<'tcx>: Sized { /// A blanket implementation of this trait (that defers to the relevant /// method of [`TypeFolder`]) is provided for all infallible folders in /// order to ensure the two APIs are coherent. -pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> { +pub trait FallibleTypeFolder<'tcx>: Sized { + type Error; + + fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error> where T: TypeFoldable<'tcx>, @@ -350,87 +197,52 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> { // delegates to infallible methods to ensure coherence. impl<'tcx, F> FallibleTypeFolder<'tcx> for F where - F: TypeFolder<'tcx, Error = !>, + F: TypeFolder<'tcx>, { - fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error> + type Error = !; + + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + TypeFolder::tcx(self) + } + + fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !> where T: TypeFoldable<'tcx>, { Ok(self.fold_binder(t)) } - fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { + fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> { Ok(self.fold_ty(t)) } - fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> { + fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> { Ok(self.fold_region(r)) } - fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> { Ok(self.fold_const(c)) } fn try_fold_unevaluated( &mut self, c: ty::Unevaluated<'tcx>, - ) -> Result<ty::Unevaluated<'tcx>, Self::Error> { + ) -> Result<ty::Unevaluated<'tcx>, !> { Ok(self.fold_unevaluated(c)) } - fn try_fold_predicate( - &mut self, - p: ty::Predicate<'tcx>, - ) -> Result<ty::Predicate<'tcx>, Self::Error> { + fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> { Ok(self.fold_predicate(p)) } fn try_fold_mir_const( &mut self, c: mir::ConstantKind<'tcx>, - ) -> Result<mir::ConstantKind<'tcx>, Self::Error> { + ) -> Result<mir::ConstantKind<'tcx>, !> { Ok(self.fold_mir_const(c)) } } -/// This trait is implemented for every visiting traversal. There is a visit -/// method defined for every type of interest. Each such method has a default -/// that recurses into the type's fields in a non-custom fashion. -pub trait TypeVisitor<'tcx>: Sized { - type BreakTy = !; - - fn visit_binder<T: TypeFoldable<'tcx>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - t.super_visit_with(self) - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - c.super_visit_with(self) - } - - fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { - uv.super_visit_with(self) - } - - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - p.super_visit_with(self) - } - - fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> { - c.super_visit_with(self) - } -} - /////////////////////////////////////////////////////////////////////////// // Some sample folders @@ -482,106 +294,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn fold_regions<T>( self, value: T, - skipped_regions: &mut bool, mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, ) -> T where T: TypeFoldable<'tcx>, { - value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) - } - - /// Invoke `callback` on every region appearing free in `value`. - pub fn for_each_free_region( - self, - value: &impl TypeFoldable<'tcx>, - mut callback: impl FnMut(ty::Region<'tcx>), - ) { - self.any_free_region_meets(value, |r| { - callback(r); - false - }); - } - - /// Returns `true` if `callback` returns true for every region appearing free in `value`. - pub fn all_free_regions_meet( - self, - value: &impl TypeFoldable<'tcx>, - mut callback: impl FnMut(ty::Region<'tcx>) -> bool, - ) -> bool { - !self.any_free_region_meets(value, |r| !callback(r)) - } - - /// Returns `true` if `callback` returns true for some region appearing free in `value`. - pub fn any_free_region_meets( - self, - value: &impl TypeFoldable<'tcx>, - callback: impl FnMut(ty::Region<'tcx>) -> bool, - ) -> bool { - struct RegionVisitor<F> { - /// The index of a binder *just outside* the things we have - /// traversed. If we encounter a bound region bound by this - /// binder or one outer to it, it appears free. Example: - /// - /// ```ignore (illustrative) - /// for<'a> fn(for<'b> fn(), T) - /// // ^ ^ ^ ^ - /// // | | | | here, would be shifted in 1 - /// // | | | here, would be shifted in 2 - /// // | | here, would be `INNERMOST` shifted in by 1 - /// // | here, initially, binder would be `INNERMOST` - /// ``` - /// - /// You see that, initially, *any* bound value is free, - /// because we've not traversed any binders. As we pass - /// through a binder, we shift the `outer_index` by 1 to - /// account for the new binder that encloses us. - outer_index: ty::DebruijnIndex, - callback: F, - } - - impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F> - where - F: FnMut(ty::Region<'tcx>) -> bool, - { - type BreakTy = (); - - fn visit_binder<T: TypeFoldable<'tcx>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.outer_index.shift_in(1); - let result = t.super_visit_with(self); - self.outer_index.shift_out(1); - result - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match *r { - ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { - ControlFlow::CONTINUE - } - _ => { - if (self.callback)(r) { - ControlFlow::BREAK - } else { - ControlFlow::CONTINUE - } - } - } - } - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // We're only interested in types involving regions - if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { - ty.super_visit_with(self) - } else { - ControlFlow::CONTINUE - } - } - } - - value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break() + value.fold_with(&mut RegionFolder::new(self, &mut f)) } } @@ -596,7 +314,6 @@ impl<'tcx> TyCtxt<'tcx> { pub struct RegionFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - skipped_regions: &'a mut bool, /// Stores the index of a binder *just outside* the stuff we have /// visited. So this begins as INNERMOST; when we pass through a @@ -614,10 +331,9 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> { #[inline] pub fn new( tcx: TyCtxt<'tcx>, - skipped_regions: &'a mut bool, fold_region_fn: &'a mut dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, ) -> RegionFolder<'a, 'tcx> { - RegionFolder { tcx, skipped_regions, current_index: ty::INNERMOST, fold_region_fn } + RegionFolder { tcx, current_index: ty::INNERMOST, fold_region_fn } } } @@ -641,7 +357,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { debug!(?self.current_index, "skipped bound region"); - *self.skipped_regions = true; r } _ => { @@ -882,45 +597,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - /// Returns a set of all late-bound regions that are constrained - /// by `value`, meaning that if we instantiate those LBR with - /// variables and equate `value` with something else, those - /// variables will also be equated. - pub fn collect_constrained_late_bound_regions<T>( - self, - value: &Binder<'tcx, T>, - ) -> FxHashSet<ty::BoundRegionKind> - where - T: TypeFoldable<'tcx>, - { - self.collect_late_bound_regions(value, true) - } - - /// Returns a set of all late-bound regions that appear in `value` anywhere. - pub fn collect_referenced_late_bound_regions<T>( - self, - value: &Binder<'tcx, T>, - ) -> FxHashSet<ty::BoundRegionKind> - where - T: TypeFoldable<'tcx>, - { - self.collect_late_bound_regions(value, false) - } - - fn collect_late_bound_regions<T>( - self, - value: &Binder<'tcx, T>, - just_constraint: bool, - ) -> FxHashSet<ty::BoundRegionKind> - where - T: TypeFoldable<'tcx>, - { - let mut collector = LateBoundRegionsCollector::new(just_constraint); - let result = value.as_ref().skip_binder().visit_with(&mut collector); - assert!(result.is_continue()); // should never have stopped early - collector.regions - } - /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions<T>(self, value: Binder<'tcx, T>) -> T @@ -961,103 +637,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -pub struct ValidateBoundVars<'tcx> { - bound_vars: &'tcx ty::List<ty::BoundVariableKind>, - binder_index: ty::DebruijnIndex, - // We may encounter the same variable at different levels of binding, so - // this can't just be `Ty` - visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, -} - -impl<'tcx> ValidateBoundVars<'tcx> { - pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self { - ValidateBoundVars { - bound_vars, - binder_index: ty::INNERMOST, - visited: SsoHashSet::default(), - } - } -} - -impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { - type BreakTy = (); - - fn visit_binder<T: TypeFoldable<'tcx>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if t.outer_exclusive_binder() < self.binder_index - || !self.visited.insert((self.binder_index, t)) - { - return ControlFlow::BREAK; - } - match *t.kind() { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - if self.bound_vars.len() <= bound_ty.var.as_usize() { - bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); - } - let list_var = self.bound_vars[bound_ty.var.as_usize()]; - match list_var { - ty::BoundVariableKind::Ty(kind) => { - if kind != bound_ty.kind { - bug!( - "Mismatched type kinds: {:?} doesn't var in list {:?}", - bound_ty.kind, - list_var - ); - } - } - _ => { - bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var) - } - } - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match *r { - ty::ReLateBound(index, br) if index == self.binder_index => { - if self.bound_vars.len() <= br.var.as_usize() { - bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars); - } - let list_var = self.bound_vars[br.var.as_usize()]; - match list_var { - ty::BoundVariableKind::Region(kind) => { - if kind != br.kind { - bug!( - "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})", - br.kind, - list_var, - self.bound_vars - ); - } - } - _ => bug!( - "Mismatched bound variable kinds! Expected region, found {:?}", - list_var - ), - } - } - - _ => (), - }; - - r.super_visit_with(self) - } -} - /////////////////////////////////////////////////////////////////////////// // Shifter // @@ -1162,301 +741,3 @@ where value.fold_with(&mut Shifter::new(tcx, amount)) } - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct FoundEscapingVars; - -/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a -/// bound region or a bound type. -/// -/// So, for example, consider a type like the following, which has two binders: -/// -/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope -/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope -/// -/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the -/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner -/// fn type*, that type has an escaping region: `'a`. -/// -/// Note that what I'm calling an "escaping var" is often just called a "free var". However, -/// we already use the term "free var". It refers to the regions or types that we use to represent -/// bound regions or type params on a fn definition while we are type checking its body. -/// -/// To clarify, conceptually there is no particular difference between -/// an "escaping" var and a "free" var. However, there is a big -/// difference in practice. Basically, when "entering" a binding -/// level, one is generally required to do some sort of processing to -/// a bound var, such as replacing it with a fresh/placeholder -/// var, or making an entry in the environment to represent the -/// scope to which it is attached, etc. An escaping var represents -/// a bound var for which this processing has not yet been done. -struct HasEscapingVarsVisitor { - /// Anything bound by `outer_index` or "above" is escaping. - outer_index: ty::DebruijnIndex, -} - -impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { - type BreakTy = FoundEscapingVars; - - fn visit_binder<T: TypeFoldable<'tcx>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.outer_index.shift_in(1); - let result = t.super_visit_with(self); - self.outer_index.shift_out(1); - result - } - - #[inline] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the outer-exclusive-binder is *strictly greater* than - // `outer_index`, that means that `t` contains some content - // bound at `outer_index` or above (because - // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. - if t.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - // If the region is bound by `outer_index` or anything outside - // of outer index, then it escapes the binders we have - // visited. - if r.bound_at_or_above_binder(self.outer_index) { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::CONTINUE - } - } - - fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - // we don't have a `visit_infer_const` callback, so we have to - // hook in here to catch this case (annoying...), but - // otherwise we do want to remember to visit the rest of the - // const, as it has types/regions embedded in a lot of other - // places. - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { - ControlFlow::Break(FoundEscapingVars) - } - _ => ct.super_visit_with(self), - } - } - - #[inline] - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - if predicate.outer_exclusive_binder() > self.outer_index { - ControlFlow::Break(FoundEscapingVars) - } else { - ControlFlow::CONTINUE - } - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -struct FoundFlags; - -// FIXME: Optimize for checking for infer flags -struct HasTypeFlagsVisitor { - flags: ty::TypeFlags, -} - -impl std::fmt::Debug for HasTypeFlagsVisitor { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.flags.fmt(fmt) - } -} - -impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - type BreakTy = FoundFlags; - - #[inline] - #[instrument(skip(self), level = "trace")] - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - let flags = t.flags(); - trace!(t.flags=?t.flags()); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - #[instrument(skip(self), level = "trace")] - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - let flags = r.type_flags(); - trace!(r.flags=?flags); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - #[instrument(level = "trace")] - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - let flags = FlagComputation::for_const(c); - trace!(r.flags=?flags); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - #[instrument(level = "trace")] - fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { - let flags = FlagComputation::for_unevaluated_const(uv); - trace!(r.flags=?flags); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - #[instrument(level = "trace")] - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - debug!( - "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", - predicate, - predicate.flags(), - self.flags - ); - if predicate.flags().intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } -} - -/// Collects all the late-bound regions at the innermost binding level -/// into a hash set. -struct LateBoundRegionsCollector { - current_index: ty::DebruijnIndex, - regions: FxHashSet<ty::BoundRegionKind>, - - /// `true` if we only want regions that are known to be - /// "constrained" when you equate this type with another type. In - /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating - /// them constraints `'a == 'b`. But if you have `<&'a u32 as - /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those - /// types may mean that `'a` and `'b` don't appear in the results, - /// so they are not considered *constrained*. - just_constrained: bool, -} - -impl LateBoundRegionsCollector { - fn new(just_constrained: bool) -> Self { - LateBoundRegionsCollector { - current_index: ty::INNERMOST, - regions: Default::default(), - just_constrained, - } - } -} - -impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder<T: TypeFoldable<'tcx>>( - &mut self, - t: &Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.current_index.shift_in(1); - let result = t.super_visit_with(self); - self.current_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - // if we are only looking for "constrained" region, we have to - // ignore the inputs to a projection, as they may not appear - // in the normalized form - if self.just_constrained { - if let ty::Projection(..) = t.kind() { - return ControlFlow::CONTINUE; - } - } - - t.super_visit_with(self) - } - - fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - // if we are only looking for "constrained" region, we have to - // ignore the inputs of an unevaluated const, as they may not appear - // in the normalized form - if self.just_constrained { - if let ty::ConstKind::Unevaluated(..) = c.kind() { - return ControlFlow::CONTINUE; - } - } - - c.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ReLateBound(debruijn, br) = *r { - if debruijn == self.current_index { - self.regions.insert(br.kind); - } - } - ControlFlow::CONTINUE - } -} - -/// Finds the max universe present -pub struct MaxUniverse { - max_universe: ty::UniverseIndex, -} - -impl MaxUniverse { - pub fn new() -> Self { - MaxUniverse { max_universe: ty::UniverseIndex::ROOT } - } - - pub fn max_universe(self) -> ty::UniverseIndex { - self.max_universe - } -} - -impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::Placeholder(placeholder) = t.kind() { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); - } - - t.super_visit_with(self) - } - - fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ConstKind::Placeholder(placeholder) = c.kind() { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); - } - - c.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::RePlaceholder(placeholder) = *r { - self.max_universe = ty::UniverseIndex::from_u32( - self.max_universe.as_u32().max(placeholder.universe.as_u32()), - ); - } - - ControlFlow::CONTINUE - } -} diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 84547dca45363..add2df25884e3 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -85,10 +85,10 @@ impl GenericParamDef { ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> { match self.kind { GenericParamDefKind::Type { has_default, .. } if has_default => { - Some(EarlyBinder(tcx.type_of(self.def_id).into())) + Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into())) } GenericParamDefKind::Const { has_default } if has_default => { - Some(EarlyBinder(tcx.const_param_default(self.def_id).into())) + Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into())) } _ => None, } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e8dd179eac198..4f9bbc135ec12 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,7 +1,9 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; +use crate::ty::{ + self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable, +}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; @@ -25,7 +27,7 @@ pub struct Instance<'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum InstanceDef<'tcx> { /// A user-defined callable item. /// @@ -496,12 +498,12 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, substs: ty::SubstsRef<'tcx>, requested_kind: ty::ClosureKind, - ) -> Instance<'tcx> { + ) -> Option<Instance<'tcx>> { let actual_kind = substs.as_closure().kind(); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs), - _ => Instance::new(def_id, substs), + _ => Some(Instance::new(def_id, substs)), } } @@ -515,7 +517,7 @@ impl<'tcx> Instance<'tcx> { tcx: TyCtxt<'tcx>, closure_did: DefId, substs: ty::SubstsRef<'tcx>, - ) -> Instance<'tcx> { + ) -> Option<Instance<'tcx>> { debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); let call_once = tcx @@ -531,12 +533,13 @@ impl<'tcx> Instance<'tcx> { let self_ty = tcx.mk_closure(closure_did, substs); let sig = substs.as_closure().sig(); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let sig = + tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?; assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); - Instance { def, substs } + Some(Instance { def, substs }) } /// Depending on the kind of `InstanceDef`, the MIR body associated with an @@ -602,7 +605,7 @@ impl<'tcx> Instance<'tcx> { /// identity parameters if they are determined to be unused in `instance.def`. pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { debug!("polymorphize: running polymorphization analysis"); - if !tcx.sess.opts.debugging_opts.polymorphize { + if !tcx.sess.opts.unstable_opts.polymorphize { return self; } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 3b05e42a53ead..c41a8318ec57f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::subst::Subst; -use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable}; use rustc_ast as ast; use rustc_attr as attr; use rustc_hir as hir; @@ -235,9 +235,8 @@ fn sanity_check_layout<'tcx>( if cfg!(debug_assertions) { fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) { match layout.abi() { - Abi::Scalar(_scalar) => { + Abi::Scalar(scalar) => { // No padding in scalars. - /* FIXME(#96185): assert_eq!( layout.align().abi, scalar.align(&tcx).abi, @@ -247,7 +246,7 @@ fn sanity_check_layout<'tcx>( layout.size(), scalar.size(&tcx), "size mismatch between ABI and layout in {layout:#?}" - );*/ + ); } Abi::Vector { count, element } => { // No padding in vectors. Alignment can be strengthened, though. @@ -543,14 +542,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { debug!("univariant offset: {:?} field: {:#?}", offset, field); offsets[i as usize] = offset; - if !repr.hide_niche() { - if let Some(mut niche) = field.largest_niche { - let available = niche.available(dl); - if available > largest_niche_available { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } + if let Some(mut niche) = field.largest_niche { + let available = niche.available(dl); + if available > largest_niche_available { + largest_niche_available = available; + niche.offset += offset; + largest_niche = Some(niche); } } @@ -1079,6 +1076,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?; st.variants = Variants::Single { index: v }; + + if def.is_unsafe_cell() { + let hide_niches = |scalar: &mut _| match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + }; + match &mut st.abi { + Abi::Uninhabited => {} + Abi::Scalar(scalar) => hide_niches(scalar), + Abi::ScalarPair(a, b) => { + hide_niches(a); + hide_niches(b); + } + Abi::Vector { element, count: _ } => hide_niches(element), + Abi::Aggregate { sized: _ } => {} + } + st.largest_niche = None; + return Ok(tcx.intern_layout(st)); + } + let (start, end) = self.tcx.layout_scalar_valid_range(def.did()); match st.abi { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { @@ -1107,11 +1127,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // Update `largest_niche` if we have introduced a larger niche. - let niche = if def.repr().hide_niche() { - None - } else { - Niche::from_scalar(dl, Size::ZERO, *scalar) - }; + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); if let Some(niche) = niche { match st.largest_niche { Some(largest_niche) => { @@ -1418,9 +1434,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { abi = Abi::Uninhabited; - } else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) { - // Without latter check aligned enums with custom discriminant values - // Would result in ICE see the issue #92464 for more info + } else if tag.size(dl) == size { + // Make sure we only use scalar layout when the enum is entirely its + // own tag (i.e. it has no padding nor any non-ZST variant fields). abi = Abi::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. @@ -1898,7 +1914,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { fn record_layout_for_printing(&self, layout: TyAndLayout<'tcx>) { // If we are running with `-Zprint-type-sizes`, maybe record layouts // for dumping later. - if self.tcx.sess.opts.debugging_opts.print_type_sizes { + if self.tcx.sess.opts.unstable_opts.print_type_sizes { self.record_layout_for_printing_outlined(layout) } } @@ -1959,7 +1975,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { min_size = field_end; } FieldInfo { - name: name.to_string(), + name, offset: offset.bytes(), size: field_layout.size.bytes(), align: field_layout.align.abi.bytes(), @@ -1968,7 +1984,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .collect(); VariantInfo { - name: n.map(|n| n.to_string()), + name: n, kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, align: layout.align.abi.bytes(), size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, @@ -2900,7 +2916,7 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: Spe // // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. - if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort { + if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort { if Some(did) == tcx.lang_items().drop_in_place_fn() { return false; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 00403ff044c40..3536d946db279 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -9,9 +9,8 @@ //! //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html -pub use self::fold::{ - FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor, -}; +pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; @@ -93,6 +92,7 @@ pub use self::sty::{ pub use self::trait_def::TraitDef; pub mod _match; +pub mod abstract_const; pub mod adjustment; pub mod binding; pub mod cast; @@ -110,6 +110,7 @@ pub mod relate; pub mod subst; pub mod trait_def; pub mod util; +pub mod visit; pub mod vtable; pub mod walk; @@ -206,7 +207,7 @@ impl MainDefinition { /// The "header" of an impl is everything outside the body: a Self type, a trait /// ref (in the case of a trait impl), and a set of predicates (from the /// bounds / where-clauses). -#[derive(Clone, Debug, TypeFoldable)] +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub struct ImplHeader<'tcx> { pub impl_def_id: DefId, pub self_ty: Ty<'tcx>, @@ -214,24 +215,14 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec<Predicate<'tcx>>, } -#[derive(Copy, Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub enum ImplSubject<'tcx> { Trait(TraitRef<'tcx>), Inherent(Ty<'tcx>), } -#[derive( - Copy, - Clone, - PartialEq, - Eq, - Hash, - TyEncodable, - TyDecodable, - HashStable, - Debug, - TypeFoldable -)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(TypeFoldable, TypeVisitable)] pub enum ImplPolarity { /// `impl Trait for Type` Positive, @@ -307,18 +298,8 @@ impl fmt::Display for BoundConstness { } } -#[derive( - Clone, - Debug, - PartialEq, - Eq, - Copy, - Hash, - TyEncodable, - TyDecodable, - HashStable, - TypeFoldable -)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] pub struct ClosureSizeProfileData<'tcx> { /// Tuple containing the types of closure captures before the feature `capture_disjoint_fields` pub before_feature_tys: Ty<'tcx>, @@ -611,8 +592,14 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { } } +impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub enum PredicateKind<'tcx> { /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -784,7 +771,7 @@ impl<'tcx> Predicate<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx>, @@ -863,7 +850,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B` pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; @@ -874,7 +861,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicat /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct SubtypePredicate<'tcx> { pub a_is_expected: bool, pub a: Ty<'tcx>, @@ -884,7 +871,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; /// Encodes that we have to coerce *from* the `a` type to the `b` type. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct CoercePredicate<'tcx> { pub a: Ty<'tcx>, pub b: Ty<'tcx>, @@ -892,7 +879,7 @@ pub struct CoercePredicate<'tcx> { pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub enum Term<'tcx> { Ty(Ty<'tcx>), Const(Const<'tcx>), @@ -914,9 +901,17 @@ impl<'tcx> Term<'tcx> { pub fn ty(&self) -> Option<Ty<'tcx>> { if let Term::Ty(ty) = self { Some(*ty) } else { None } } + pub fn ct(&self) -> Option<Const<'tcx>> { if let Term::Const(c) = self { Some(*c) } else { None } } + + pub fn into_arg(self) -> GenericArg<'tcx> { + match self { + Term::Ty(ty) => ty.into(), + Term::Const(c) => c.into(), + } + } } /// This kind of predicate has no *direct* correspondent in the @@ -932,7 +927,7 @@ impl<'tcx> Term<'tcx> { /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, pub term: Term<'tcx>, @@ -1038,6 +1033,24 @@ impl<'tcx> Predicate<'tcx> { } } + pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> { + let predicate = self.kind(); + match predicate.skip_binder() { + PredicateKind::Projection(t) => Some(predicate.rebind(t)), + PredicateKind::Trait(..) + | PredicateKind::Subtype(..) + | PredicateKind::Coerce(..) + | PredicateKind::RegionOutlives(..) + | PredicateKind::WellFormed(..) + | PredicateKind::ObjectSafe(..) + | PredicateKind::ClosureKind(..) + | PredicateKind::TypeOutlives(..) + | PredicateKind::ConstEvaluatable(..) + | PredicateKind::ConstEquate(..) + | PredicateKind::TypeWellFormedFromEnv(..) => None, + } + } + pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { @@ -1076,7 +1089,7 @@ impl<'tcx> Predicate<'tcx> { /// `[[], [U:Bar<T>]]`. Now if there were some particular reference /// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[], /// [usize:Bar<isize>]]`. -#[derive(Clone, Debug, TypeFoldable)] +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub struct InstantiatedPredicates<'tcx> { pub predicates: Vec<Predicate<'tcx>>, pub spans: Vec<Span>, @@ -1092,24 +1105,15 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -#[derive( - Copy, - Clone, - Debug, - PartialEq, - Eq, - HashStable, - TyEncodable, - TyDecodable, - TypeFoldable, - Lift -)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct OpaqueTypeKey<'tcx> { + // FIXME(oli-obk): make this a LocalDefId pub def_id: DefId, pub substs: SubstsRef<'tcx>, } -#[derive(Copy, Clone, Debug, TypeFoldable, HashStable, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So /// for example: @@ -1245,7 +1249,7 @@ pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>; /// except that instead of a `Ty` we bundle the `DefId` of the const parameter. /// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some` /// to get the type of `did`. -#[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, TyEncodable, TyDecodable)] #[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(Hash, HashStable)] pub struct WithOptConstParam<T> { @@ -1401,7 +1405,9 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { self.constness().try_fold_with(folder)?, )) } +} +impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.caller_bounds().visit_with(visitor)?; self.reveal().visit_with(visitor)?; @@ -1528,7 +1534,7 @@ impl<'tcx> ParamEnv<'tcx> { /// `where Box<u32>: Copy`, which are clearly never /// satisfiable. We generally want to behave as if they were true, /// although the surrounding function is never reachable. - pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> { + pub fn and<T: TypeVisitable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> { match self.reveal() { Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, @@ -1561,7 +1567,7 @@ impl<'tcx> PolyTraitRef<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, pub value: T, @@ -1733,11 +1739,9 @@ bitflags! { const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. const IS_LINEAR = 1 << 3; - // If true, don't expose any niche to type's context. - const HIDE_NICHE = 1 << 4; // If true, the type's layout can be randomized using // the seed stored in `ReprOptions.layout_seed` - const RANDOMIZE_LAYOUT = 1 << 5; + const RANDOMIZE_LAYOUT = 1 << 4; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits @@ -1776,7 +1780,7 @@ impl ReprOptions { // If the user defined a custom seed for layout randomization, xor the item's // path hash with the user defined seed, this will allowing determinism while // still allowing users to further randomize layout generation for e.g. fuzzing - if let Some(user_seed) = tcx.sess.opts.debugging_opts.layout_seed { + if let Some(user_seed) = tcx.sess.opts.unstable_opts.layout_seed { field_shuffle_seed ^= user_seed; } @@ -1794,7 +1798,6 @@ impl ReprOptions { ReprFlags::empty() } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, - attr::ReprNoNiche => ReprFlags::HIDE_NICHE, attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprInt(i) => { size = Some(i); @@ -1810,7 +1813,7 @@ impl ReprOptions { // If `-Z randomize-layout` was enabled for the type definition then we can // consider performing layout randomization - if tcx.sess.opts.debugging_opts.randomize_layout { + if tcx.sess.opts.unstable_opts.randomize_layout { flags.insert(ReprFlags::RANDOMIZE_LAYOUT); } @@ -1847,11 +1850,6 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_LINEAR) } - #[inline] - pub fn hide_niche(&self) -> bool { - self.flags.contains(ReprFlags::HIDE_NICHE) - } - /// Returns the discriminant type, given these `repr` options. /// This must only be called on enums! pub fn discr_type(&self) -> attr::IntType { diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9bbbd7e2f7c5e..9d8a811659433 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -112,6 +112,26 @@ impl<'tcx> TyCtxt<'tcx> { self.normalize_erasing_regions(param_env, value) } + /// If you have a `Binder<'tcx, T>`, you can do this to strip out the + /// late-bound regions and then normalize the result, yielding up + /// a `T` (with regions erased). This is appropriate when the + /// binder is being instantiated at the call site. + /// + /// N.B., currently, higher-ranked type bounds inhibit + /// normalization. Therefore, each time we erase them in + /// codegen, we need to normalize the contents. + pub fn try_normalize_erasing_late_bound_regions<T>( + self, + param_env: ty::ParamEnv<'tcx>, + value: ty::Binder<'tcx, T>, + ) -> Result<T, NormalizationError<'tcx>> + where + T: TypeFoldable<'tcx>, + { + let value = self.erase_late_bound_regions(value); + self.try_normalize_erasing_regions(param_env, value) + } + /// Monomorphizes a type from the AST by first applying the /// in-scope substitutions and then normalizing any associated /// types. @@ -228,15 +248,13 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { } } -impl<'tcx> TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { +impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { type Error = NormalizationError<'tcx>; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } -} -impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) { Ok(t) => Ok(t.expect_ty()), diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 54ba9e84fdb7b..e189ee2fc4db1 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -3,7 +3,7 @@ use rustc_index::vec::{Idx, IndexVec}; use crate::middle::exported_symbols::ExportedSymbol; use crate::mir::Body; -use crate::thir::abstract_const::Node; +use crate::ty::abstract_const::Node; use crate::ty::{ self, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty, }; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 200253d575599..96e84bc8f0acf 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2,7 +2,7 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{ self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, }; use rustc_apfloat::ieee::{Double, Single}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -226,7 +226,7 @@ pub trait PrettyPrinter<'tcx>: value.as_ref().skip_binder().print(self) } - fn wrap_binder<T, F: Fn(&T, Self) -> Result<Self, fmt::Error>>( + fn wrap_binder<T, F: FnOnce(&T, Self) -> Result<Self, fmt::Error>>( self, value: &ty::Binder<'tcx, T>, f: F, @@ -297,7 +297,7 @@ pub trait PrettyPrinter<'tcx>: mut self, def_id: DefId, ) -> Result<(Self::Path, bool), Self::Error> { - if !self.tcx().sess.opts.debugging_opts.trim_diagnostic_paths + if !self.tcx().sess.opts.unstable_opts.trim_diagnostic_paths || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never) || NO_TRIMMED_PATH.with(|flag| flag.get()) || SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) @@ -712,7 +712,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("closure")); // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { - if self.tcx().sess.opts.debugging_opts.span_free_formats { + if self.tcx().sess.opts.unstable_opts.span_free_formats { p!("@", print_def_path(did.to_def_id(), substs)); } else { let span = self.tcx().def_span(did); @@ -773,18 +773,18 @@ pub trait PrettyPrinter<'tcx>: def_id: DefId, substs: &'tcx ty::List<ty::GenericArg<'tcx>>, ) -> Result<Self::Type, Self::Error> { - define_scoped_cx!(self); + let tcx = self.tcx(); // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let bounds = self.tcx().bound_explicit_item_bounds(def_id); + let bounds = tcx.bound_explicit_item_bounds(def_id); let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); let mut is_sized = false; for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { - let predicate = predicate.subst(self.tcx(), substs); + let predicate = predicate.subst(tcx, substs); let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -792,7 +792,7 @@ pub trait PrettyPrinter<'tcx>: let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print + Sized, but rather + ?Sized if absent. - if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() { + if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { is_sized = true; continue; } @@ -801,7 +801,7 @@ pub trait PrettyPrinter<'tcx>: } ty::PredicateKind::Projection(pred) => { let proj_ref = bound_predicate.rebind(pred); - let trait_ref = proj_ref.required_poly_trait_ref(self.tcx()); + let trait_ref = proj_ref.required_poly_trait_ref(tcx); // Projection type entry -- the def-id for naming, and the ty. let proj_ty = (proj_ref.projection_def_id(), proj_ref.term()); @@ -817,148 +817,155 @@ pub trait PrettyPrinter<'tcx>: } } + write!(self, "impl ")?; + let mut first = true; // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized; - p!("impl"); - for (fn_once_trait_ref, entry) in fn_traits { - // Get the (single) generic ty (the args) of this FnOnce trait ref. - let generics = self.tcx().generics_of(fn_once_trait_ref.def_id()); - let args = - generics.own_substs_no_defaults(self.tcx(), fn_once_trait_ref.skip_binder().substs); - - match (entry.return_ty, args[0].expect_ty()) { - // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded - // a return type. - (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => { - let name = if entry.fn_trait_ref.is_some() { - "Fn" - } else if entry.fn_mut_trait_ref.is_some() { - "FnMut" - } else { - "FnOnce" - }; + write!(self, "{}", if first { "" } else { " + " })?; + write!(self, "{}", if paren_needed { "(" } else { "" })?; - p!( - write("{}", if first { " " } else { " + " }), - write("{}{}(", if paren_needed { "(" } else { "" }, name) - ); + self = self.wrap_binder(&fn_once_trait_ref, |trait_ref, mut cx| { + define_scoped_cx!(cx); + // Get the (single) generic ty (the args) of this FnOnce trait ref. + let generics = tcx.generics_of(trait_ref.def_id); + let args = generics.own_substs_no_defaults(tcx, trait_ref.substs); + + match (entry.return_ty, args[0].expect_ty()) { + // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded + // a return type. + (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => { + let name = if entry.fn_trait_ref.is_some() { + "Fn" + } else if entry.fn_mut_trait_ref.is_some() { + "FnMut" + } else { + "FnOnce" + }; - for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() { - if idx > 0 { - p!(", "); + p!(write("{}(", name)); + + for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() { + if idx > 0 { + p!(", "); + } + p!(print(ty)); } - p!(print(ty)); - } - p!(")"); - if let Term::Ty(ty) = return_ty.skip_binder() { - if !ty.is_unit() { - p!(" -> ", print(return_ty)); + p!(")"); + if let Term::Ty(ty) = return_ty.skip_binder() { + if !ty.is_unit() { + p!(" -> ", print(return_ty)); + } } - } - p!(write("{}", if paren_needed { ")" } else { "" })); + p!(write("{}", if paren_needed { ")" } else { "" })); - first = false; - } - // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the - // trait_refs we collected in the OpaqueFnEntry as normal trait refs. - _ => { - if entry.has_fn_once { - traits.entry(fn_once_trait_ref).or_default().extend( - // Group the return ty with its def id, if we had one. - entry - .return_ty - .map(|ty| (self.tcx().lang_items().fn_once_output().unwrap(), ty)), - ); - } - if let Some(trait_ref) = entry.fn_mut_trait_ref { - traits.entry(trait_ref).or_default(); + first = false; } - if let Some(trait_ref) = entry.fn_trait_ref { - traits.entry(trait_ref).or_default(); + // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the + // trait_refs we collected in the OpaqueFnEntry as normal trait refs. + _ => { + if entry.has_fn_once { + traits.entry(fn_once_trait_ref).or_default().extend( + // Group the return ty with its def id, if we had one. + entry + .return_ty + .map(|ty| (tcx.lang_items().fn_once_output().unwrap(), ty)), + ); + } + if let Some(trait_ref) = entry.fn_mut_trait_ref { + traits.entry(trait_ref).or_default(); + } + if let Some(trait_ref) = entry.fn_trait_ref { + traits.entry(trait_ref).or_default(); + } } } - } + + Ok(cx) + })?; } // Print the rest of the trait types (that aren't Fn* family of traits) for (trait_ref, assoc_items) in traits { - p!( - write("{}", if first { " " } else { " + " }), - print(trait_ref.skip_binder().print_only_trait_name()) - ); + write!(self, "{}", if first { "" } else { " + " })?; + + self = self.wrap_binder(&trait_ref, |trait_ref, mut cx| { + define_scoped_cx!(cx); + p!(print(trait_ref.print_only_trait_name())); - let generics = self.tcx().generics_of(trait_ref.def_id()); - let args = generics.own_substs_no_defaults(self.tcx(), trait_ref.skip_binder().substs); + let generics = tcx.generics_of(trait_ref.def_id); + let args = generics.own_substs_no_defaults(tcx, trait_ref.substs); - if !args.is_empty() || !assoc_items.is_empty() { - let mut first = true; + if !args.is_empty() || !assoc_items.is_empty() { + let mut first = true; - for ty in args { - if first { - p!("<"); - first = false; - } else { - p!(", "); + for ty in args { + if first { + p!("<"); + first = false; + } else { + p!(", "); + } + p!(print(ty)); } - p!(print(trait_ref.rebind(*ty))); - } - for (assoc_item_def_id, term) in assoc_items { - // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks, - // unless we can find out what generator return type it comes from. - let term = if let Some(ty) = term.skip_binder().ty() - && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind() - && Some(*item_def_id) == self.tcx().lang_items().generator_return() - { - if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { - let return_ty = substs.as_generator().return_ty(); - if !return_ty.is_ty_infer() { - return_ty.into() + for (assoc_item_def_id, term) in assoc_items { + // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks, + // unless we can find out what generator return type it comes from. + let term = if let Some(ty) = term.skip_binder().ty() + && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind() + && Some(*item_def_id) == tcx.lang_items().generator_return() + { + if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { + let return_ty = substs.as_generator().return_ty(); + if !return_ty.is_ty_infer() { + return_ty.into() + } else { + continue; + } } else { continue; } } else { - continue; - } - } else { - term.skip_binder() - }; + term.skip_binder() + }; - if first { - p!("<"); - first = false; - } else { - p!(", "); - } + if first { + p!("<"); + first = false; + } else { + p!(", "); + } - p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name)); + p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); - match term { - Term::Ty(ty) => { - p!(print(ty)) - } - Term::Const(c) => { - p!(print(c)); - } - }; - } + match term { + Term::Ty(ty) => { + p!(print(ty)) + } + Term::Const(c) => { + p!(print(c)); + } + }; + } - if !first { - p!(">"); + if !first { + p!(">"); + } } - } - first = false; + first = false; + Ok(cx) + })?; } if !is_sized { - p!(write("{}?Sized", if first { " " } else { " + " })); + write!(self, "{}?Sized", if first { "" } else { " + " })?; } else if first { - p!(" Sized"); + write!(self, "Sized")?; } Ok(self) @@ -1023,11 +1030,11 @@ pub trait PrettyPrinter<'tcx>: } } - fn ty_infer_name(&self, _: ty::TyVid) -> Option<String> { + fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } - fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<String> { + fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> { None } @@ -1348,10 +1355,6 @@ pub trait PrettyPrinter<'tcx>: " as ", )?; } - // For function type zsts just printing the path is enough - ty::FnDef(d, s) if int == ScalarInt::ZST => { - p!(print_value_path(*d, s)) - } // Nontrivial types with scalar bit representation _ => { let print = |mut this: Self| { @@ -1440,7 +1443,11 @@ pub trait PrettyPrinter<'tcx>: p!(write("{:?}", String::from_utf8_lossy(bytes))); return Ok(self); } - _ => {} + _ => { + p!("&"); + p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty)); + return Ok(self); + } }, (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| { @@ -1452,16 +1459,8 @@ pub trait PrettyPrinter<'tcx>: } // Aggregates, printed as array/tuple/struct/variant construction syntax. (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { - let Some(contents) = self.tcx().try_destructure_const( - ty::Const::from_value(self.tcx(), valtree, ty) - ) else { - // Fall back to debug pretty printing for invalid constants. - p!(write("{:?}", valtree)); - if print_ty { - p!(": ", print(ty)); - } - return Ok(self); - }; + let contents = + self.tcx().destructure_const(ty::Const::from_value(self.tcx(), valtree, ty)); let fields = contents.fields.iter().copied(); match *ty.kind() { ty::Array(..) => { @@ -1551,8 +1550,8 @@ pub struct FmtPrinterData<'a, 'tcx> { pub region_highlight_mode: RegionHighlightMode<'tcx>, - pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<String> + 'a>>, - pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<String> + 'a>>, + pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>, + pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>, } impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> { @@ -1842,11 +1841,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { - fn ty_infer_name(&self, id: ty::TyVid) -> Option<String> { + fn ty_infer_name(&self, id: ty::TyVid) -> Option<Symbol> { self.0.ty_infer_name_resolver.as_ref().and_then(|func| func(id)) } - fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<String> { + fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> { self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id)) } @@ -1869,7 +1868,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { self.pretty_in_binder(value) } - fn wrap_binder<T, C: Fn(&T, Self) -> Result<Self, Self::Error>>( + fn wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, Self::Error>>( self, value: &ty::Binder<'tcx, T>, f: C, @@ -1920,7 +1919,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { return true; } - let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions; + let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions; match *region { ty::ReEarlyBound(ref data) => { @@ -1993,7 +1992,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { return Ok(self); } - let identify_regions = self.tcx.sess.opts.debugging_opts.identify_regions; + let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions; // These printouts are concise. They do not contain all the information // the user might want to diagnose an error, but there is basically no way @@ -2256,7 +2255,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { Ok(inner) } - pub fn pretty_wrap_binder<T, C: Fn(&T, Self) -> Result<Self, fmt::Error>>( + pub fn pretty_wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, fmt::Error>>( self, value: &ty::Binder<'tcx, T>, f: C, @@ -2274,14 +2273,14 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>) where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { struct LateBoundRegionNameCollector<'a, 'tcx> { used_region_names: &'a mut FxHashSet<Symbol>, type_collector: SsoHashSet<Ty<'tcx>>, } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { type BreakTy = (); fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -2385,7 +2384,7 @@ macro_rules! define_print_and_forward_display { /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait path. That is, it will print `Trait<U>` instead of /// `<T as Trait<U>>`. -#[derive(Copy, Clone, TypeFoldable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>); impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { @@ -2397,7 +2396,7 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait name. That is, it will print `Trait` instead of /// `<T as Trait<U>>`. -#[derive(Copy, Clone, TypeFoldable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>); impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> { @@ -2422,7 +2421,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { } } -#[derive(Copy, Clone, TypeFoldable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>); impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 51980acd38f74..818affa7113a1 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -345,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { } } -#[derive(Copy, Debug, Clone, TypeFoldable)] +#[derive(Copy, Debug, Clone, TypeFoldable, TypeVisitable)] struct GeneratorWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>); impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8ba5b882fdd57..391a0a20c9662 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -4,8 +4,9 @@ use crate::mir::interpret; use crate::mir::ProjectionKind; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; +use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; use rustc_hir as hir; @@ -183,7 +184,7 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { // For things that don't carry any arena-allocated data (and are // copy...), just add them to this list. -TrivialTypeFoldableAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { (), bool, usize, @@ -452,7 +453,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T> where - <T as Lift<'tcx>>::Lifted: TypeFoldable<'tcx>, + <T as Lift<'tcx>>::Lifted: TypeVisitable<'tcx>, { type Lifted = ty::Binder<'tcx, T::Lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { @@ -651,7 +652,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> { Ok(self) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } @@ -664,7 +667,9 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ) -> Result<(T, U), F::Error> { Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?)) } +} +impl<'tcx, T: TypeVisitable<'tcx>, U: TypeVisitable<'tcx>> TypeVisitable<'tcx> for (T, U) { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.0.visit_with(visitor)?; self.1.visit_with(visitor) @@ -684,7 +689,11 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> self.2.try_fold_with(folder)?, )) } +} +impl<'tcx, A: TypeVisitable<'tcx>, B: TypeVisitable<'tcx>, C: TypeVisitable<'tcx>> + TypeVisitable<'tcx> for (A, B, C) +{ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.0.visit_with(visitor)?; self.1.visit_with(visitor)?; @@ -692,19 +701,31 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> } } -EnumTypeFoldableImpl! { +EnumTypeTraversalImpl! { impl<'tcx, T> TypeFoldable<'tcx> for Option<T> { (Some)(a), (None), } where T: TypeFoldable<'tcx> } +EnumTypeTraversalImpl! { + impl<'tcx, T> TypeVisitable<'tcx> for Option<T> { + (Some)(a), + (None), + } where T: TypeVisitable<'tcx> +} -EnumTypeFoldableImpl! { +EnumTypeTraversalImpl! { impl<'tcx, T, E> TypeFoldable<'tcx> for Result<T, E> { (Ok)(a), (Err)(a), } where T: TypeFoldable<'tcx>, E: TypeFoldable<'tcx>, } +EnumTypeTraversalImpl! { + impl<'tcx, T, E> TypeVisitable<'tcx> for Result<T, E> { + (Ok)(a), + (Err)(a), + } where T: TypeVisitable<'tcx>, E: TypeVisitable<'tcx>, +} impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>( @@ -744,7 +765,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> { Ok(Rc::from_raw(Rc::into_raw(unique).cast())) } } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Rc<T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } @@ -788,7 +811,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> { Ok(Arc::from_raw(Arc::into_raw(unique).cast())) } } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Arc<T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } @@ -798,7 +823,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_id(|value| value.try_fold_with(folder)) } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { (**self).visit_with(visitor) } @@ -808,7 +835,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_id(|t| t.try_fold_with(folder)) } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec<T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } @@ -818,7 +847,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_id(|t| t.try_fold_with(folder)) } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } @@ -828,7 +859,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_bound(|ty| ty.try_fold_with(folder)) } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::EarlyBinder<T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.as_ref().0.visit_with(visitor) } @@ -838,7 +871,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_binder(self) } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::Binder<'tcx, T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_binder(self) } @@ -851,7 +886,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<'tcx> for ty::Binder<'tcx, T ) -> Result<Self, F::Error> { self.try_map_bound(|ty| ty.try_fold_with(folder)) } +} +impl<'tcx, T: TypeVisitable<'tcx>> TypeSuperVisitable<'tcx> for ty::Binder<'tcx, T> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.as_ref().skip_binder().visit_with(visitor) } @@ -861,7 +898,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::Existentia fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v)) } +} +impl<'tcx> TypeVisitable<'tcx> + for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> +{ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|p| p.visit_with(visitor)) } @@ -871,7 +912,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v)) } +} +impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ProjectionKind> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } @@ -903,7 +946,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { }, }) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { use crate::ty::InstanceDef::*; self.substs.visit_with(visitor)?; @@ -929,7 +974,9 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted }) } +} +impl<'tcx> TypeVisitable<'tcx> for interpret::GlobalId<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.instance.visit_with(visitor) } @@ -939,7 +986,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_ty(self) } +} +impl<'tcx> TypeVisitable<'tcx> for Ty<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_ty(*self) } @@ -989,7 +1038,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }) } +} +impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), @@ -1037,7 +1088,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_region(self) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::Region<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_region(*self) } @@ -1050,7 +1103,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> { ) -> Result<Self, F::Error> { Ok(self) } +} +impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } @@ -1060,7 +1115,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_predicate(self) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::Predicate<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_predicate(*self) } @@ -1069,6 +1126,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { self.outer_exclusive_binder() > binder } + #[inline] fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { self.flags().intersects(flags) } @@ -1082,7 +1140,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Predicate<'tcx> { let new = self.kind().try_fold_with(folder)?; Ok(folder.tcx().reuse_or_mk_predicate(self, new)) } +} +impl<'tcx> TypeSuperVisitable<'tcx> for ty::Predicate<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.kind().visit_with(visitor) } @@ -1092,7 +1152,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v)) } +} +impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|p| p.visit_with(visitor)) } @@ -1102,7 +1164,9 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { self.try_map_id(|x| x.try_fold_with(folder)) } +} +impl<'tcx, T: TypeVisitable<'tcx>, I: Idx> TypeVisitable<'tcx> for IndexVec<I, T> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } @@ -1112,7 +1176,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_const(self) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::Const<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_const(*self) } @@ -1131,7 +1197,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Const<'tcx> { Ok(self) } } +} +impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.ty().visit_with(visitor)?; self.kind().visit_with(visitor) @@ -1150,7 +1218,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { | ty::ConstKind::Error(_) => self, }) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::ConstKind<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), @@ -1168,7 +1238,9 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> { Ok(self) } +} +impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } @@ -1178,7 +1250,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { folder.try_fold_unevaluated(self) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_unevaluated(*self) } @@ -1195,7 +1269,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Unevaluated<'tcx> { promoted: self.promoted, }) } +} +impl<'tcx> TypeSuperVisitable<'tcx> for ty::Unevaluated<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.substs.visit_with(visitor) } @@ -1205,7 +1281,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { Ok(self.expand().try_fold_with(folder)?.shrink()) } +} +impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.expand().visit_with(visitor) } @@ -1215,7 +1293,9 @@ impl<'tcx> TypeFoldable<'tcx> for hir::Constness { fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { Ok(self) } +} +impl<'tcx> TypeVisitable<'tcx> for hir::Constness { fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { ControlFlow::CONTINUE } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 296442e243607..d663f1a3ec6e7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -3,11 +3,11 @@ #![allow(rustc::usage_of_ty_tykind)] use crate::infer::canonical::Canonical; -use crate::ty::fold::ValidateBoundVars; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; +use crate::ty::visit::ValidateBoundVars; use crate::ty::InferTy::*; use crate::ty::{ - self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperFoldable, + self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use crate::ty::{List, ParamEnv}; @@ -38,7 +38,7 @@ pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>; pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TypeAndMut<'tcx> { pub ty: Ty<'tcx>, pub mutbl: hir::Mutability, @@ -201,7 +201,7 @@ static_assert_size!(TyKind<'_>, 32); /// * `GR`: The "return type", which is the type of value returned upon /// completion of the generator. /// * `GW`: The "generator witness". -#[derive(Copy, Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with a tuple containing the types of the upvars. @@ -328,7 +328,7 @@ impl<'tcx> ClosureSubsts<'tcx> { } /// Similar to `ClosureSubsts`; see the above documentation for more. -#[derive(Copy, Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GeneratorSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } @@ -608,7 +608,7 @@ impl<'tcx> UpvarSubsts<'tcx> { /// type of the constant. The reason that `R` is represented as an extra type parameter /// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters: /// inline const can reference lifetimes that are internal to the creating function. -#[derive(Copy, Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct InlineConstSubsts<'tcx> { /// Generic parameters from the enclosing item, /// concatenated with the inferred type of the constant. @@ -655,7 +655,7 @@ impl<'tcx> InlineConstSubsts<'tcx> { } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub enum ExistentialPredicate<'tcx> { /// E.g., `Iterator`. Trait(ExistentialTraitRef<'tcx>), @@ -781,7 +781,7 @@ impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> { /// Trait references also appear in object types like `Foo<U>`, but in /// that case the `Self` parameter is absent from the substitutions. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct TraitRef<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -853,7 +853,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// The substitutions don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -932,6 +932,10 @@ impl<T> EarlyBinder<T> { let value = f(self.0)?; Ok(EarlyBinder(value)) } + + pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> { + EarlyBinder(value) + } } impl<T> EarlyBinder<Option<T>> { @@ -986,7 +990,7 @@ pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>); impl<'tcx, T> Binder<'tcx, T> where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { /// Wraps `value` in a binder, asserting that `value` does not /// contain any bound vars that would be bound by the @@ -1050,14 +1054,14 @@ impl<'tcx, T> Binder<'tcx, T> { Binder(value, self.1) } - pub fn map_bound_ref<F, U: TypeFoldable<'tcx>>(&self, f: F) -> Binder<'tcx, U> + pub fn map_bound_ref<F, U: TypeVisitable<'tcx>>(&self, f: F) -> Binder<'tcx, U> where F: FnOnce(&T) -> U, { self.as_ref().map_bound(f) } - pub fn map_bound<F, U: TypeFoldable<'tcx>>(self, f: F) -> Binder<'tcx, U> + pub fn map_bound<F, U: TypeVisitable<'tcx>>(self, f: F) -> Binder<'tcx, U> where F: FnOnce(T) -> U, { @@ -1069,7 +1073,7 @@ impl<'tcx, T> Binder<'tcx, T> { Binder(value, self.1) } - pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E> + pub fn try_map_bound<F, U: TypeVisitable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E> where F: FnOnce(T) -> Result<U, E>, { @@ -1092,7 +1096,7 @@ impl<'tcx, T> Binder<'tcx, T> { /// in `bind`. This may be (debug) asserted in the future. pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U> where - U: TypeFoldable<'tcx>, + U: TypeVisitable<'tcx>, { if cfg!(debug_assertions) { let mut validator = ValidateBoundVars::new(self.bound_vars()); @@ -1113,7 +1117,7 @@ impl<'tcx, T> Binder<'tcx, T> { /// would not be that useful.) pub fn no_bound_vars(self) -> Option<T> where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } @@ -1143,7 +1147,7 @@ impl<'tcx, T> Binder<'tcx, Option<T>> { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `<T as Trait<..>>::N`. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: SubstsRef<'tcx>, @@ -1192,7 +1196,7 @@ impl<'tcx> ProjectionTy<'tcx> { } } -#[derive(Copy, Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, @@ -1208,7 +1212,7 @@ pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>; /// - `output`: is the return type. /// - `c_variadic`: indicates whether this is a C-variadic function. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx List<Ty<'tcx>>, pub c_variadic: bool, @@ -1315,6 +1319,7 @@ pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); impl<'tcx> Deref for Region<'tcx> { type Target = RegionKind<'tcx>; + #[inline] fn deref(&self) -> &RegionKind<'tcx> { &self.0.0 } @@ -1385,7 +1390,7 @@ impl From<BoundVar> for BoundTy { /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct ExistentialProjection<'tcx> { pub item_def_id: DefId, pub substs: SubstsRef<'tcx>, @@ -1570,6 +1575,19 @@ impl<'tcx> Region<'tcx> { _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), } } + + /// True for free regions other than `'static`. + pub fn is_free(self) -> bool { + matches!(*self, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + + /// True if `self` is a free region or static. + pub fn is_free_or_static(self) -> bool { + match *self { + ty::ReStatic => true, + _ => self.is_free(), + } + } } /// Type utilities diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index ad2898ccd67ba..3a524d7b0f307 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -2,10 +2,9 @@ use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::fold::{ - FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor, -}; +use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; +use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_data_structures::intern::{Interned, WithStableHash}; @@ -205,7 +204,9 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), } } +} +impl<'tcx> TypeVisitable<'tcx> for GenericArg<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), @@ -449,7 +450,9 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_substs(v)), } } +} +impl<'tcx> TypeVisitable<'tcx> for SubstsRef<'tcx> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } @@ -485,7 +488,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)), } } +} +impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<Ty<'tcx>> { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.iter().try_for_each(|t| t.visit_with(visitor)) } @@ -705,7 +710,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { return val; } - let result = ty::fold::shift_vars(self.tcx(), val, self.binders_passed); + let result = ty::fold::shift_vars(TypeFolder::tcx(self), val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result @@ -722,7 +727,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { /// Stores the user-given substs to reach some fully qualified path /// (e.g., `<T>::Item` or `<T as Trait>::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct UserSubsts<'tcx> { /// The substitutions for the item as given by the user. pub substs: SubstsRef<'tcx>, @@ -749,7 +754,7 @@ pub struct UserSubsts<'tcx> { /// the self type, giving `Foo<?A>`. Finally, we unify that with /// the self type here, which contains `?A` to be `&'static u32` #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct UserSelfTy<'tcx> { pub impl_def_id: DefId, pub self_ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index cb34b64660d2b..826c16dda4aa7 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,6 +1,6 @@ use crate::traits::specialization_graph; use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use crate::ty::fold::TypeFoldable; +use crate::ty::visit::TypeVisitable; use crate::ty::{Ident, Ty, TyCtxt}; use hir::def_id::LOCAL_CRATE; use rustc_hir as hir; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 38846031badab..4d2f69b23fa09 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,6 +6,7 @@ use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::{ self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitable, }; use rustc_apfloat::Float as _; use rustc_ast as ast; @@ -141,16 +142,16 @@ impl<'tcx> TyCtxt<'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = StableHasher::new(); - let mut hcx = self.create_stable_hashing_context(); - // We want the type_id be independent of the types free regions, so we // erase them. The erase_regions() call will also anonymize bound // regions, which is desirable too. let ty = self.erase_regions(ty); - hcx.while_hashing_spans(false, |hcx| ty.hash_stable(hcx, &mut hasher)); - hasher.finish() + self.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + hcx.while_hashing_spans(false, |hcx| ty.hash_stable(hcx, &mut hasher)); + hasher.finish() + }) } pub fn res_generics_def_id(self, res: Res) -> Option<DefId> { @@ -675,6 +676,10 @@ impl<'tcx> TyCtxt<'tcx> { ) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> { ty::EarlyBinder(self.item_bounds(def_id)) } + + pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> { + ty::EarlyBinder(self.const_param_default(def_id)) + } } struct OpaqueTypeExpander<'tcx> { @@ -1041,6 +1046,7 @@ impl<'tcx> Ty<'tcx> { ty } + #[inline] pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex { self.0.outer_exclusive_binder } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs new file mode 100644 index 0000000000000..5365067209af9 --- /dev/null +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -0,0 +1,745 @@ +//! A visiting traversal mechanism for complex data structures that contain type +//! information. +//! +//! This is a read-only traversal of the data structure. +//! +//! This traversal has limited flexibility. Only a small number of "types of +//! interest" within the complex data structures can receive custom +//! visitation. These are the ones containing the most important type-related +//! information, such as `Ty`, `Predicate`, `Region`, and `Const`. +//! +//! There are three groups of traits involved in each traversal. +//! - `TypeVisitable`. This is implemented once for many types, including: +//! - Types of interest, for which the the methods delegate to the +//! visitor. +//! - All other types, including generic containers like `Vec` and `Option`. +//! It defines a "skeleton" of how they should be visited. +//! - `TypeSuperVisitable`. This is implemented only for each type of interest, +//! and defines the visiting "skeleton" for these types. +//! - `TypeVisitor`. This is implemented for each visitor. This defines how +//! types of interest are visited. +//! +//! This means each visit is a mixture of (a) generic visiting operations, and (b) +//! custom visit operations that are specific to the visitor. +//! - The `TypeVisitable` impls handle most of the traversal, and call into +//! `TypeVisitor` when they encounter a type of interest. +//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of +//! the types of interest are recursive and can contain other types of interest. +//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each +//! visitor might provide custom handling only for some types of interest, or +//! only for some variants of each type of interest, and then use default +//! traversal for the remaining cases. +//! +//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U: +//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so: +//! ```text +//! s.visit_with(visitor) calls +//! - ty.visit_with(visitor) calls +//! - visitor.visit_ty(ty) may call +//! - ty.super_visit_with(visitor) +//! - u.visit_with(visitor) +//! ``` +use crate::mir; +use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; +use rustc_errors::ErrorGuaranteed; + +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sso::SsoHashSet; +use std::fmt; +use std::ops::ControlFlow; + +/// This trait is implemented for every type that can be visited, +/// providing the skeleton of the traversal. +/// +/// To implement this conveniently, use the derive macro located in +/// `rustc_macros`. +pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { + /// The entry point for visiting. To visit a value `t` with a visitor `v` + /// call: `t.visit_with(v)`. + /// + /// For most types, this just traverses the value, calling `visit_with` on + /// each field/element. + /// + /// For types of interest (such as `Ty`), the implementation of this method + /// that calls a visitor method specifically for that type (such as + /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to + /// `TypeVisitor`. + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; + + /// Returns `true` if `self` has any late-bound regions that are either + /// bound by `binder` or bound by some binder outside of `binder`. + /// If `binder` is `ty::INNERMOST`, this indicates whether + /// there are any late-bound regions that appear free. + fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { + self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() + } + + /// Returns `true` if this `self` has any regions that escape `binder` (and + /// hence are not bound by it). + fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { + self.has_vars_bound_at_or_above(binder.shifted_in(1)) + } + + fn has_escaping_bound_vars(&self) -> bool { + self.has_vars_bound_at_or_above(ty::INNERMOST) + } + + #[instrument(level = "trace")] + fn has_type_flags(&self, flags: TypeFlags) -> bool { + self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) + } + fn has_projections(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_PROJECTION) + } + fn has_opaque_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) + } + fn references_error(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_ERROR) + } + fn error_reported(&self) -> Option<ErrorGuaranteed> { + if self.references_error() { + Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()) + } else { + None + } + } + fn has_param_types_or_consts(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) + } + fn has_infer_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_INFER) + } + fn has_infer_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER) + } + fn has_infer_types_or_consts(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER) + } + fn needs_infer(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_INFER) + } + fn has_placeholders(&self) -> bool { + self.has_type_flags( + TypeFlags::HAS_RE_PLACEHOLDER + | TypeFlags::HAS_TY_PLACEHOLDER + | TypeFlags::HAS_CT_PLACEHOLDER, + ) + } + fn needs_subst(&self) -> bool { + self.has_type_flags(TypeFlags::NEEDS_SUBST) + } + /// "Free" regions in this context means that it has any region + /// that is not (a) erased or (b) late-bound. + fn has_free_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + } + + fn has_erased_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_ERASED) + } + + /// True if there are any un-erased free regions. + fn has_erasable_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) + } + + /// Indicates whether this value references only 'global' + /// generic parameters that are the same regardless of what fn we are + /// in. This is used for caching. + fn is_global(&self) -> bool { + !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) + } + + /// True if there are any late-bound regions + fn has_late_bound_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND) + } + + /// Indicates whether this value still has parameters/placeholders/inference variables + /// which could be replaced later, in a way that would change the results of `impl` + /// specialization. + fn still_further_specializable(&self) -> bool { + self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) + } +} + +pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> { + /// Provides a default visit for a type of interest. This should only be + /// called within `TypeVisitor` methods, when a non-custom traversal is + /// desired for the value of the type of interest passed to that method. + /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call + /// `ty.super_visit_with(self)`, but any other visiting should be done + /// with `xyz.visit_with(self)`. + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; +} + +/// This trait is implemented for every visiting traversal. There is a visit +/// method defined for every type of interest. Each such method has a default +/// that recurses into the type's fields in a non-custom fashion. +pub trait TypeVisitor<'tcx>: Sized { + type BreakTy = !; + + fn visit_binder<T: TypeVisitable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + t.super_visit_with(self) + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + r.super_visit_with(self) + } + + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + c.super_visit_with(self) + } + + fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { + uv.super_visit_with(self) + } + + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { + p.super_visit_with(self) + } + + fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> { + c.super_visit_with(self) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Region folder + +impl<'tcx> TyCtxt<'tcx> { + /// Invoke `callback` on every region appearing free in `value`. + pub fn for_each_free_region( + self, + value: &impl TypeVisitable<'tcx>, + mut callback: impl FnMut(ty::Region<'tcx>), + ) { + self.any_free_region_meets(value, |r| { + callback(r); + false + }); + } + + /// Returns `true` if `callback` returns true for every region appearing free in `value`. + pub fn all_free_regions_meet( + self, + value: &impl TypeVisitable<'tcx>, + mut callback: impl FnMut(ty::Region<'tcx>) -> bool, + ) -> bool { + !self.any_free_region_meets(value, |r| !callback(r)) + } + + /// Returns `true` if `callback` returns true for some region appearing free in `value`. + pub fn any_free_region_meets( + self, + value: &impl TypeVisitable<'tcx>, + callback: impl FnMut(ty::Region<'tcx>) -> bool, + ) -> bool { + struct RegionVisitor<F> { + /// The index of a binder *just outside* the things we have + /// traversed. If we encounter a bound region bound by this + /// binder or one outer to it, it appears free. Example: + /// + /// ```ignore (illustrative) + /// for<'a> fn(for<'b> fn(), T) + /// // ^ ^ ^ ^ + /// // | | | | here, would be shifted in 1 + /// // | | | here, would be shifted in 2 + /// // | | here, would be `INNERMOST` shifted in by 1 + /// // | here, initially, binder would be `INNERMOST` + /// ``` + /// + /// You see that, initially, *any* bound value is free, + /// because we've not traversed any binders. As we pass + /// through a binder, we shift the `outer_index` by 1 to + /// account for the new binder that encloses us. + outer_index: ty::DebruijnIndex, + callback: F, + } + + impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F> + where + F: FnMut(ty::Region<'tcx>) -> bool, + { + type BreakTy = (); + + fn visit_binder<T: TypeVisitable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.outer_index.shift_in(1); + let result = t.super_visit_with(self); + self.outer_index.shift_out(1); + result + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + match *r { + ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { + ControlFlow::CONTINUE + } + _ => { + if (self.callback)(r) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } + } + } + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + // We're only interested in types involving regions + if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { + ty.super_visit_with(self) + } else { + ControlFlow::CONTINUE + } + } + } + + value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break() + } + + /// Returns a set of all late-bound regions that are constrained + /// by `value`, meaning that if we instantiate those LBR with + /// variables and equate `value` with something else, those + /// variables will also be equated. + pub fn collect_constrained_late_bound_regions<T>( + self, + value: &Binder<'tcx, T>, + ) -> FxHashSet<ty::BoundRegionKind> + where + T: TypeVisitable<'tcx>, + { + self.collect_late_bound_regions(value, true) + } + + /// Returns a set of all late-bound regions that appear in `value` anywhere. + pub fn collect_referenced_late_bound_regions<T>( + self, + value: &Binder<'tcx, T>, + ) -> FxHashSet<ty::BoundRegionKind> + where + T: TypeVisitable<'tcx>, + { + self.collect_late_bound_regions(value, false) + } + + fn collect_late_bound_regions<T>( + self, + value: &Binder<'tcx, T>, + just_constraint: bool, + ) -> FxHashSet<ty::BoundRegionKind> + where + T: TypeVisitable<'tcx>, + { + let mut collector = LateBoundRegionsCollector::new(just_constraint); + let result = value.as_ref().skip_binder().visit_with(&mut collector); + assert!(result.is_continue()); // should never have stopped early + collector.regions + } +} + +pub struct ValidateBoundVars<'tcx> { + bound_vars: &'tcx ty::List<ty::BoundVariableKind>, + binder_index: ty::DebruijnIndex, + // We may encounter the same variable at different levels of binding, so + // this can't just be `Ty` + visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, +} + +impl<'tcx> ValidateBoundVars<'tcx> { + pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self { + ValidateBoundVars { + bound_vars, + binder_index: ty::INNERMOST, + visited: SsoHashSet::default(), + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { + type BreakTy = (); + + fn visit_binder<T: TypeVisitable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.binder_index.shift_in(1); + let result = t.super_visit_with(self); + self.binder_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if t.outer_exclusive_binder() < self.binder_index + || !self.visited.insert((self.binder_index, t)) + { + return ControlFlow::BREAK; + } + match *t.kind() { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + if self.bound_vars.len() <= bound_ty.var.as_usize() { + bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); + } + let list_var = self.bound_vars[bound_ty.var.as_usize()]; + match list_var { + ty::BoundVariableKind::Ty(kind) => { + if kind != bound_ty.kind { + bug!( + "Mismatched type kinds: {:?} doesn't var in list {:?}", + bound_ty.kind, + list_var + ); + } + } + _ => { + bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var) + } + } + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + match *r { + ty::ReLateBound(index, br) if index == self.binder_index => { + if self.bound_vars.len() <= br.var.as_usize() { + bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars); + } + let list_var = self.bound_vars[br.var.as_usize()]; + match list_var { + ty::BoundVariableKind::Region(kind) => { + if kind != br.kind { + bug!( + "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})", + br.kind, + list_var, + self.bound_vars + ); + } + } + _ => bug!( + "Mismatched bound variable kinds! Expected region, found {:?}", + list_var + ), + } + } + + _ => (), + }; + + r.super_visit_with(self) + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundEscapingVars; + +/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a +/// bound region or a bound type. +/// +/// So, for example, consider a type like the following, which has two binders: +/// +/// for<'a> fn(x: for<'b> fn(&'a isize, &'b isize)) +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope +/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ inner scope +/// +/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the +/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner +/// fn type*, that type has an escaping region: `'a`. +/// +/// Note that what I'm calling an "escaping var" is often just called a "free var". However, +/// we already use the term "free var". It refers to the regions or types that we use to represent +/// bound regions or type params on a fn definition while we are type checking its body. +/// +/// To clarify, conceptually there is no particular difference between +/// an "escaping" var and a "free" var. However, there is a big +/// difference in practice. Basically, when "entering" a binding +/// level, one is generally required to do some sort of processing to +/// a bound var, such as replacing it with a fresh/placeholder +/// var, or making an entry in the environment to represent the +/// scope to which it is attached, etc. An escaping var represents +/// a bound var for which this processing has not yet been done. +struct HasEscapingVarsVisitor { + /// Anything bound by `outer_index` or "above" is escaping. + outer_index: ty::DebruijnIndex, +} + +impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { + type BreakTy = FoundEscapingVars; + + fn visit_binder<T: TypeVisitable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.outer_index.shift_in(1); + let result = t.super_visit_with(self); + self.outer_index.shift_out(1); + result + } + + #[inline] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + // If the outer-exclusive-binder is *strictly greater* than + // `outer_index`, that means that `t` contains some content + // bound at `outer_index` or above (because + // `outer_exclusive_binder` is always 1 higher than the + // content in `t`). Therefore, `t` has some escaping vars. + if t.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::CONTINUE + } + } + + #[inline] + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + // If the region is bound by `outer_index` or anything outside + // of outer index, then it escapes the binders we have + // visited. + if r.bound_at_or_above_binder(self.outer_index) { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::CONTINUE + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + // we don't have a `visit_infer_const` callback, so we have to + // hook in here to catch this case (annoying...), but + // otherwise we do want to remember to visit the rest of the + // const, as it has types/regions embedded in a lot of other + // places. + match ct.kind() { + ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { + ControlFlow::Break(FoundEscapingVars) + } + _ => ct.super_visit_with(self), + } + } + + #[inline] + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { + if predicate.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::CONTINUE + } + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct FoundFlags; + +// FIXME: Optimize for checking for infer flags +struct HasTypeFlagsVisitor { + flags: ty::TypeFlags, +} + +impl std::fmt::Debug for HasTypeFlagsVisitor { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.flags.fmt(fmt) + } +} + +impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { + type BreakTy = FoundFlags; + + #[inline] + #[instrument(skip(self), level = "trace")] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + let flags = t.flags(); + trace!(t.flags=?t.flags()); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } + } + + #[inline] + #[instrument(skip(self), level = "trace")] + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + let flags = r.type_flags(); + trace!(r.flags=?flags); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } + } + + #[inline] + #[instrument(level = "trace")] + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + let flags = FlagComputation::for_const(c); + trace!(r.flags=?flags); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } + } + + #[inline] + #[instrument(level = "trace")] + fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> { + let flags = FlagComputation::for_unevaluated_const(uv); + trace!(r.flags=?flags); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } + } + + #[inline] + #[instrument(level = "trace")] + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { + debug!( + "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", + predicate, + predicate.flags(), + self.flags + ); + if predicate.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::CONTINUE + } + } +} + +/// Collects all the late-bound regions at the innermost binding level +/// into a hash set. +struct LateBoundRegionsCollector { + current_index: ty::DebruijnIndex, + regions: FxHashSet<ty::BoundRegionKind>, + + /// `true` if we only want regions that are known to be + /// "constrained" when you equate this type with another type. In + /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating + /// them constraints `'a == 'b`. But if you have `<&'a u32 as + /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those + /// types may mean that `'a` and `'b` don't appear in the results, + /// so they are not considered *constrained*. + just_constrained: bool, +} + +impl LateBoundRegionsCollector { + fn new(just_constrained: bool) -> Self { + LateBoundRegionsCollector { + current_index: ty::INNERMOST, + regions: Default::default(), + just_constrained, + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { + fn visit_binder<T: TypeVisitable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.current_index.shift_in(1); + let result = t.super_visit_with(self); + self.current_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + // if we are only looking for "constrained" region, we have to + // ignore the inputs to a projection, as they may not appear + // in the normalized form + if self.just_constrained { + if let ty::Projection(..) = t.kind() { + return ControlFlow::CONTINUE; + } + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + // if we are only looking for "constrained" region, we have to + // ignore the inputs of an unevaluated const, as they may not appear + // in the normalized form + if self.just_constrained { + if let ty::ConstKind::Unevaluated(..) = c.kind() { + return ControlFlow::CONTINUE; + } + } + + c.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::ReLateBound(debruijn, br) = *r { + if debruijn == self.current_index { + self.regions.insert(br.kind); + } + } + ControlFlow::CONTINUE + } +} + +/// Finds the max universe present +pub struct MaxUniverse { + max_universe: ty::UniverseIndex, +} + +impl MaxUniverse { + pub fn new() -> Self { + MaxUniverse { max_universe: ty::UniverseIndex::ROOT } + } + + pub fn max_universe(self) -> ty::UniverseIndex { + self.max_universe + } +} + +impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::Placeholder(placeholder) = t.kind() { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::ConstKind::Placeholder(placeholder) = c.kind() { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + c.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::RePlaceholder(placeholder) = *r { + self.max_universe = ty::UniverseIndex::from_u32( + self.max_universe.as_u32().max(placeholder.universe.as_u32()), + ); + } + + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 998b80a36c2f7..30f90e383a889 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -23,4 +23,4 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ast = { path = "../rustc_ast" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index a83328c0cabc6..cb8be51a08562 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref pattern, initializer, lint_level, + else_block, } => { let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); @@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |this| { let scope = (*init_scope, source_info); this.in_scope(scope, *lint_level, |this| { - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - ArmHasGuard(false), - Some((None, initializer_span)), - ); - this.expr_into_pattern(block, pattern.clone(), init) + if let Some(else_block) = else_block { + this.ast_let_else( + block, + init, + initializer_span, + else_block, + visibility_scope, + remainder_span, + pattern, + ) + } else { + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); + this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern + } }) - } + }, ) - ); + ) } else { let scope = (*init_scope, source_info); unpack!(this.in_scope(scope, *lint_level, |this| { diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 3d6e50f0c0622..648d10b9e42a8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -49,11 +49,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: ty, }) }); - let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty); Constant { span, user_ty: user_ty, literal } } + ExprKind::ZstLiteral { user_ty } => { + let user_ty = user_ty.map(|user_ty| { + this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { + span, + user_ty, + inferred_ty: ty, + }) + }); + let literal = ConstantKind::Val(ConstValue::ZeroSized, ty); + + Constant { span, user_ty: user_ty, literal } + } ExprKind::NamedConst { def_id, substs, user_ty } => { let user_ty = user_ty.map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index e77f5931dd65d..6abf419dd4991 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::place::Projection as HirProjection; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; +use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -71,7 +72,7 @@ pub(crate) enum PlaceBase { /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. #[derive(Clone, Debug, PartialEq)] -pub(crate) struct PlaceBuilder<'tcx> { +pub(in crate::build) struct PlaceBuilder<'tcx> { base: PlaceBase, projection: Vec<PlaceElem<'tcx>>, } @@ -104,6 +105,8 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( variant = Some(*idx); continue; } + // These do not affect anything, they just make sure we know the right type. + ProjectionElem::OpaqueCast(_) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -201,10 +204,10 @@ fn find_capture_matching_projections<'a, 'tcx>( /// `PlaceBuilder` now starts from `PlaceBase::Local`. /// /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found. -fn to_upvars_resolved_place_builder<'a, 'tcx>( +#[instrument(level = "trace", skip(cx))] +fn to_upvars_resolved_place_builder<'tcx>( from_builder: PlaceBuilder<'tcx>, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + cx: &Builder<'_, 'tcx>, ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { match from_builder.base { PlaceBase::Local(_) => Ok(from_builder), @@ -219,13 +222,13 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( let Some((capture_index, capture)) = find_capture_matching_projections( - typeck_results, + cx.typeck_results, var_hir_id, closure_def_id, &from_builder.projection, ) else { - let closure_span = tcx.def_span(closure_def_id); - if !enable_precise_capture(tcx, closure_span) { + let closure_span = cx.tcx.def_span(closure_def_id); + if !enable_precise_capture(cx.tcx, closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -242,8 +245,8 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( }; // We won't be building MIR if the closure wasn't local - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); - let closure_ty = typeck_results.node_type(closure_hir_id); + let closure_hir_id = cx.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let closure_ty = cx.typeck_results.node_type(closure_hir_id); let substs = match closure_ty.kind() { ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), @@ -270,12 +273,14 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( // We used some of the projections to build the capture itself, // now we apply the remaining to the upvar resolved place. + trace!(?capture.place, ?from_builder.projection); let remaining_projections = strip_prefix( capture.place.base_ty, from_builder.projection, &capture.place.projections, ); upvar_resolved_place_builder.projection.extend(remaining_projections); + trace!(?upvar_resolved_place_builder); Ok(upvar_resolved_place_builder) } @@ -294,16 +299,21 @@ fn strip_prefix<'tcx>( prefix_projections: &[HirProjection<'tcx>], ) -> impl Iterator<Item = PlaceElem<'tcx>> { let mut iter = projections.into_iter(); + let mut next = || match iter.next()? { + // Filter out opaque casts, they are unnecessary in the prefix. + ProjectionElem::OpaqueCast(..) => iter.next(), + other => Some(other), + }; for projection in prefix_projections { match projection.kind { HirProjectionKind::Deref => { - assert!(matches!(iter.next(), Some(ProjectionElem::Deref))); + assert!(matches!(next(), Some(ProjectionElem::Deref))); } HirProjectionKind::Field(..) => { if base_ty.is_enum() { - assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..)))); + assert!(matches!(next(), Some(ProjectionElem::Downcast(..)))); } - assert!(matches!(iter.next(), Some(ProjectionElem::Field(..)))); + assert!(matches!(next(), Some(ProjectionElem::Field(..)))); } HirProjectionKind::Index | HirProjectionKind::Subslice => { bug!("unexpected projection kind: {:?}", projection); @@ -315,24 +325,32 @@ fn strip_prefix<'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - pub(crate) fn into_place<'a>( - self, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> Place<'tcx> { + pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> { if let PlaceBase::Local(local) = self.base { - Place { local, projection: tcx.intern_place_elems(&self.projection) } + let mut projections = vec![]; + let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty); + for projection in self.projection { + // Only preserve those opaque casts that actually go from an opaque type + // to another type. + if let ProjectionElem::OpaqueCast(t) = projection { + if let ty::Opaque(..) = ty.ty.kind() { + if t != ty.ty { + projections.push(ProjectionElem::OpaqueCast(t)); + } + } + } else { + projections.push(projection); + } + ty = ty.projection_ty(cx.tcx, projection); + } + Place { local, projection: cx.tcx.intern_place_elems(&projections) } } else { - self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results) + self.expect_upvars_resolved(cx).into_place(cx) } } - fn expect_upvars_resolved<'a>( - self, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> PlaceBuilder<'tcx> { - to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() + fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> { + to_upvars_resolved_place_builder(self, cx).unwrap() } /// Attempts to resolve the `PlaceBuilder`. @@ -346,12 +364,11 @@ impl<'tcx> PlaceBuilder<'tcx> { /// not captured. This can happen because the final mir that will be /// generated doesn't require a read for this place. Failures will only /// happen inside closures. - pub(crate) fn try_upvars_resolved<'a>( + pub(crate) fn try_upvars_resolved( self, - tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, + cx: &Builder<'_, 'tcx>, ) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { - to_upvars_resolved_place_builder(self, tcx, typeck_results) + to_upvars_resolved_place_builder(self, cx) } pub(crate) fn base(&self) -> PlaceBase { @@ -411,7 +428,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.tcx, self.typeck_results)) + block.and(place_builder.into_place(self)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -435,7 +452,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self.tcx, self.typeck_results)) + block.and(place_builder.into_place(self)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -530,7 +547,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this.tcx, this.typeck_results); + let place = place_builder.clone().into_place(this); this.cfg.push( block, Statement { @@ -603,6 +620,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Literal { .. } | ExprKind::NamedConst { .. } | ExprKind::NonHirLiteral { .. } + | ExprKind::ZstLiteral { .. } | ExprKind::ConstParam { .. } | ExprKind::ConstBlock { .. } | ExprKind::StaticRef { .. } @@ -681,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { - base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results); + base_place = base_place.expect_upvars_resolved(self); self.add_fake_borrows_of_base( &base_place, block, @@ -709,12 +727,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lt = self.temp(bool_ty, expr_span); // len = len(slice) - self.cfg.push_assign( - block, - source_info, - len, - Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)), - ); + self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self))); // lt = idx < len self.cfg.push_assign( block, @@ -794,6 +807,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => (), } 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 8e87ecd27d285..93f76333165a5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -1,6 +1,7 @@ //! See docs in `build/expr/mod.rs`. use rustc_index::vec::Idx; +use rustc_middle::ty::util::IntTypeExt; use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; @@ -190,7 +191,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Cast { source } => { let source = &this.thir[source]; - let from_ty = CastTy::from_ty(source.ty); + + // Casting an enum to an integer is equivalent to computing the discriminant and casting the + // discriminant. Previously every backend had to repeat the logic for this operation. Now we + // create all the steps directly in MIR with operations all backends need to support anyway. + let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() { + let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx); + let place = unpack!(block = this.as_place(block, source)); + let discr = this.temp(discr_ty, source.span); + this.cfg.push_assign( + block, + source_info, + discr, + Rvalue::Discriminant(place), + ); + + (Operand::Move(discr), discr_ty) + } else { + let ty = source.ty; + let source = unpack!( + block = this.as_operand(block, scope, source, None, NeedsTemporary::No) + ); + (source, ty) + }; + let from_ty = CastTy::from_ty(ty); let cast_ty = CastTy::from_ty(expr.ty); let cast_kind = match (from_ty, cast_ty) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { @@ -201,9 +225,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } (_, _) => CastKind::Misc, }; - let source = unpack!( - block = this.as_operand(block, scope, source, None, NeedsTemporary::No) - ); block.and(Rvalue::Cast(cast_kind, source, expr.ty)) } ExprKind::Pointer { cast, source } => { @@ -300,11 +321,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place_builder = unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); - if let Ok(place_builder_resolved) = - place_builder.try_upvars_resolved(this.tcx, this.typeck_results) - { - let mir_place = - place_builder_resolved.into_place(this.tcx, this.typeck_results); + if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) { + let mir_place = place_builder_resolved.into_place(this); this.cfg.push_fake_read( block, this.source_info(this.tcx.hir().span(*hir_id)), @@ -394,6 +412,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Literal { .. } | ExprKind::NamedConst { .. } | ExprKind::NonHirLiteral { .. } + | ExprKind::ZstLiteral { .. } | ExprKind::ConstParam { .. } | ExprKind::ConstBlock { .. } | ExprKind::StaticRef { .. } => { @@ -594,8 +613,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // by the parent itself. The mutability of the current capture // is same as that of the capture in the parent closure. PlaceBase::Upvar { .. } => { - let enclosing_upvars_resolved = - arg_place_builder.clone().into_place(this.tcx, this.typeck_results); + let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this); match enclosing_upvars_resolved.as_ref() { PlaceRef { @@ -632,7 +650,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; - let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results); + let arg_place = arg_place_builder.into_place(this); this.cfg.push_assign( block, 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 724b72f8769b8..dac8862647a85 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -23,6 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability)) } + #[instrument(skip(self), level = "debug")] fn as_temp_inner( &mut self, mut block: BasicBlock, @@ -30,10 +31,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, mutability: Mutability, ) -> BlockAnd<Local> { - debug!( - "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", - block, temp_lifetime, expr, mutability - ); let this = self; let expr_span = expr.span; diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index b1a706439342e..a4386319dc1aa 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -72,6 +72,7 @@ impl Category { ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::NonHirLiteral { .. } + | ExprKind::ZstLiteral { .. } | ExprKind::ConstParam { .. } | ExprKind::StaticRef { .. } | ExprKind::NamedConst { .. } => Some(Category::Constant), diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index cffb67ef01328..d1ef515b3d29b 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -15,14 +15,13 @@ use std::iter; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. + #[instrument(level = "debug", skip(self))] pub(crate) fn expr_into_dest( &mut self, destination: Place<'tcx>, mut block: BasicBlock, expr: &Expr<'tcx>, ) -> BlockAnd<()> { - debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr); - // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to // just use the name `this` uniformly @@ -366,9 +365,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None => { let place_builder = place_builder.clone(); this.consume_by_copy_or_move( - place_builder - .field(n, *ty) - .into_place(this.tcx, this.typeck_results), + place_builder.field(n, *ty).into_place(this), ) } }) @@ -559,6 +556,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Literal { .. } | ExprKind::NamedConst { .. } | ExprKind::NonHirLiteral { .. } + | ExprKind::ZstLiteral { .. } | ExprKind::ConstParam { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::StaticRef { .. } => { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 1628f1a4b850b..86ef666eac8d2 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -220,10 +220,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause_matched_place = FakeReadCause::ForMatchedPlace(None); let source_info = self.source_info(scrutinee_span); - if let Ok(scrutinee_builder) = - scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { - let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results); + if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) { + let scrutinee_place = scrutinee_builder.into_place(self); self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); } @@ -348,12 +346,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; let scrutinee_place: Place<'tcx>; - if let Ok(scrutinee_builder) = scrutinee_place_builder - .clone() - .try_upvars_resolved(this.tcx, this.typeck_results) + if let Ok(scrutinee_builder) = + scrutinee_place_builder.clone().try_upvars_resolved(this) { - scrutinee_place = - scrutinee_builder.into_place(this.tcx, this.typeck_results); + scrutinee_place = scrutinee_builder.into_place(this); opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); } let scope = this.declare_bindings( @@ -602,12 +598,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { while let Some(next) = { for binding in &candidate_ref.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); - - let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, - )))) = self.local_decls[local].local_info else { - bug!("Let binding to non-user variable.") - }; // `try_upvars_resolved` may fail if it is unable to resolve the given // `PlaceBuilder` inside a closure. In this case, we don't want to include // a scrutinee place. `scrutinee_place_builder` will fail for destructured @@ -622,10 +612,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let (v1, v2) = foo; // }; // ``` - if let Ok(match_pair_resolved) = - initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { - let place = match_pair_resolved.into_place(self.tcx, self.typeck_results); + if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) { + let place = match_pair_resolved.into_place(self); + + let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, + )))) = self.local_decls[local].local_info else { + bug!("Let binding to non-user variable.") + }; + *match_place = Some(place); } } @@ -654,6 +649,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// scope for the bindings in these patterns, if such a scope had to be /// created. NOTE: Declaring the bindings should always be done in their /// drop scope. + #[instrument(skip(self), level = "debug")] pub(crate) fn declare_bindings( &mut self, mut visibility_scope: Option<SourceScope>, @@ -662,7 +658,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { has_guard: ArmHasGuard, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option<SourceScope> { - debug!("declare_bindings: pattern={:?}", pattern); self.visit_primary_bindings( &pattern, UserTypeProjections::none(), @@ -872,7 +867,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { Candidate { span: pattern.span, has_guard, - match_pairs: smallvec![MatchPair { place, pattern }], + match_pairs: smallvec![MatchPair::new(place, pattern)], bindings: Vec::new(), ascriptions: Vec::new(), subcandidates: Vec::new(), @@ -1048,6 +1043,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// if `x.0` matches `false` (for the third arm). In the (impossible at /// runtime) case when `x.0` is now `true`, we branch to /// `otherwise_block`. + #[instrument(skip(self, fake_borrows), level = "debug")] fn match_candidates<'pat>( &mut self, span: Span, @@ -1057,11 +1053,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'pat, 'tcx>], fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, ) { - debug!( - "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})", - span, candidates, start_block, otherwise_block, - ); - // Start by simplifying candidates. Once this process is complete, all // the match pairs which remain require some form of test, whether it // be a switch or pattern comparison. @@ -1380,6 +1371,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) } + #[instrument( + skip(self, otherwise, or_span, place, fake_borrows, candidate, pats), + level = "debug" + )] fn test_or_pattern<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, @@ -1389,7 +1384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: PlaceBuilder<'tcx>, fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>, ) { - debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats); + debug!("candidate={:#?}\npats={:#?}", candidate, pats); let mut or_candidates: Vec<_> = pats .iter() .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard)) @@ -1605,9 +1600,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Insert a Shallow borrow of any places that is switched on. if let Some(fb) = fake_borrows && let Ok(match_place_resolved) = - match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results) + match_place.clone().try_upvars_resolved(self) { - let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results); + let resolved_place = match_place_resolved.into_place(self); fb.insert(resolved_place); } @@ -1615,7 +1610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // those N possible outcomes, create a (initially empty) // vector of candidates. Those are the candidates that still // apply if the test has that particular outcome. - debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair); + debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair); let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![]; target_candidates.resize_with(test.targets(), Default::default); @@ -1634,7 +1629,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates = rest; } // at least the first candidate ought to be tested - assert!(total_candidate_count > candidates.len()); + assert!( + total_candidate_count > candidates.len(), + "{}, {:#?}", + total_candidate_count, + candidates + ); debug!("tested_candidates: {}", total_candidate_count - candidates.len()); debug!("untested_candidates: {}", candidates.len()); @@ -1794,10 +1794,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None; let expr_place: Place<'tcx>; - if let Ok(expr_builder) = - expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results) - { - expr_place = expr_builder.into_place(self.tcx, self.typeck_results); + if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) { + expr_place = expr_builder.into_place(self); opt_expr_place = Some((Some(&expr_place), expr_span)); } let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); @@ -2195,6 +2193,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// first local is a binding for occurrences of `var` in the guard, which /// will have type `&T`. The second local is a binding for occurrences of /// `var` in the arm body, which will have type `T`. + #[instrument(skip(self), level = "debug")] fn declare_binding( &mut self, source_info: SourceInfo, @@ -2209,19 +2208,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_match_place: Option<(Option<Place<'tcx>>, Span)>, pat_span: Span, ) { - debug!( - "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ - visibility_scope={:?}, source_info={:?})", - var_id, name, mode, var_ty, visibility_scope, source_info - ); - let tcx = self.tcx; let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; let binding_mode = match mode { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability), BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability), }; - debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { mutability, ty: var_ty, @@ -2271,7 +2263,78 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { LocalsForNode::One(for_arm_body) }; - debug!("declare_binding: vars={:?}", locals); + debug!(?locals); self.var_indices.insert(var_id, locals); } + + pub(crate) fn ast_let_else( + &mut self, + mut block: BasicBlock, + init: &Expr<'tcx>, + initializer_span: Span, + else_block: &Block, + visibility_scope: Option<SourceScope>, + remainder_span: Span, + pattern: &Pat<'tcx>, + ) -> BlockAnd<()> { + let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span)); + let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; + let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); + self.declare_bindings( + visibility_scope, + remainder_span, + pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); + let mut candidate = Candidate::new(scrutinee.clone(), pattern, false); + let fake_borrow_temps = self.lower_match_tree( + block, + initializer_span, + pattern.span, + false, + &mut [&mut candidate, &mut wildcard], + ); + // This block is for the matching case + let matching = self.bind_pattern( + self.source_info(pattern.span), + candidate, + None, + &fake_borrow_temps, + initializer_span, + None, + None, + None, + ); + // This block is for the failure case + let failure = self.bind_pattern( + self.source_info(else_block.span), + wildcard, + None, + &fake_borrow_temps, + initializer_span, + None, + None, + None, + ); + // This place is not really used because this destination place + // should never be used to take values at the end of the failure + // block. + let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() }; + let failure_block; + unpack!( + failure_block = self.ast_block( + dummy_place, + failure, + else_block, + self.source_info(else_block.span), + ) + ); + self.cfg.terminate( + failure_block, + self.source_info(else_block.span), + TerminatorKind::Unreachable, + ); + matching.unit() + } } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index c6298904140c3..6fa817da28a3c 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -37,12 +37,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// only generates a single switch. If this happens this method returns /// `true`. + #[instrument(skip(self, candidate), level = "debug")] pub(super) fn simplify_candidate<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, ) -> bool { // repeatedly simplify match pairs until fixed point is reached - debug!(?candidate, "simplify_candidate"); + debug!("{:#?}", candidate); // existing_bindings and new_bindings exists to keep the semantics in order. // Reversing the binding order for bindings after `@` changes the binding order in places @@ -155,12 +156,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::Ascription { ref annotation, variance }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the - if let Ok(place_resolved) = - match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { + if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), - source: place_resolved.into_place(self.tcx, self.typeck_results), + source: place_resolved.into_place(self), variance, }); } @@ -184,12 +183,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, is_primary: _, } => { - if let Ok(place_resolved) = - match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results) - { + if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { candidate.bindings.push(Binding { span: match_pair.pattern.span, - source: place_resolved.into_place(self.tcx, self.typeck_results), + source: place_resolved.into_place(self), var_id: var, binding_mode: mode, }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 598da80c574af..63acd731db7c9 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -144,6 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")] pub(super) fn perform_test( &mut self, match_start_span: Span, @@ -153,21 +154,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { test: &Test<'tcx>, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, ) { - let place: Place<'tcx>; - if let Ok(test_place_builder) = - place_builder.try_upvars_resolved(self.tcx, self.typeck_results) - { - place = test_place_builder.into_place(self.tcx, self.typeck_results); - } else { - return; - } - debug!( - "perform_test({:?}, {:?}: {:?}, {:?})", - block, - place, - place.ty(&self.local_decls, self.tcx), - test - ); + let place = place_builder.into_place(self); + let place_ty = place.ty(&self.local_decls, self.tcx); + debug!(?place, ?place_ty,); let source_info = self.source_info(test.span); match test.kind { @@ -735,9 +724,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let elem = - ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index); - let downcast_place = match_pair.place.project(elem); // `(x as Variant)` + let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter().map(|subpattern| { // e.g., `(x as Variant).0` let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 9a1e98d3bb18d..4a7edc517f4e4 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -31,21 +31,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Pat<'tcx>], ) { let tcx = self.tcx; - let (min_length, exact_size) = if let Ok(place_resolved) = - place.clone().try_upvars_resolved(tcx, self.typeck_results) - { - match place_resolved - .into_place(tcx, self.typeck_results) - .ty(&self.local_decls, tcx) - .ty - .kind() - { - ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; + let (min_length, exact_size) = + if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) { + match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() { + ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = @@ -100,10 +94,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - pub(crate) fn new( + pub(in crate::build) fn new( place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, ) -> MatchPair<'pat, 'tcx> { + // Force the place type to the pattern's type. + // FIXME(oli-obk): only do this when we don't already know the place type. + // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? + let place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); MatchPair { place, pattern } } } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e239981892912..7ae26cccb3848 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_span::Symbol; @@ -68,9 +68,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ // Figure out what primary body this item has. let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) { - Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { fn_decl, body, .. }, .. }) => { - (*body, fn_decl.output.span(), None) - } + Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { fn_decl, body, .. }), + .. + }) => (*body, fn_decl.output.span(), None), Node::Item(hir::Item { kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id), span, @@ -162,7 +163,11 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ let opt_ty_info; let self_arg; if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) { - opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span); + opt_ty_info = fn_decl + .inputs + .get(index) + // Make sure that inferred closure args have no type span + .and_then(|ty| if arg.pat.span != ty.span { Some(ty.span) } else { None }); self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() { match fn_decl.implicit_self { hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm), @@ -993,7 +998,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { continue; }; let pat = match tcx.hir().get(arg.pat.hir_id) { - Node::Pat(pat) | Node::Binding(pat) => pat, + Node::Pat(pat) => pat, node => bug!("pattern became {:?}", node), }; let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b9fd8c50e6a04..ab37c4802852a 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -553,6 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience wrapper that pushes a scope and then executes `f` /// to build its contents, popping the scope afterwards. + #[instrument(skip(self, f), level = "debug")] pub(crate) fn in_scope<F, R>( &mut self, region_scope: (region::Scope, SourceInfo), @@ -562,7 +563,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>, { - debug!("in_scope(region_scope={:?})", region_scope); let source_scope = self.source_scope; let tcx = self.tcx; if let LintLevel::Explicit(current_hir_id) = lint_level { @@ -589,7 +589,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(region_scope, block)); self.source_scope = source_scope; - debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block); + debug!(?block); block.and(rv) } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 94b2722dca86d..89f60902cf9d2 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -307,6 +307,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Literal { .. } | ExprKind::NamedConst { .. } | ExprKind::NonHirLiteral { .. } + | ExprKind::ZstLiteral { .. } | ExprKind::ConstParam { .. } | ExprKind::ConstBlock { .. } | ExprKind::Deref { .. } @@ -430,16 +431,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { let lhs = &self.thir[lhs]; if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() { if let Some((assigned_ty, assignment_span)) = self.assignment_info { - // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. - if !(assigned_ty - .ty_adt_def() - .map_or(false, |adt| adt.is_manually_drop()) - || assigned_ty - .is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env)) - { - self.requires_unsafe(assignment_span, AssignToDroppingUnionField); - } else { - // write to non-drop union field, safe + if assigned_ty.needs_drop(self.tcx, self.tcx.param_env(adt_def.did())) { + // This would be unsafe, but should be outright impossible since we reject such unions. + self.tcx.sess.delay_span_bug(assignment_span, "union fields that need dropping should be impossible"); } } else { self.requires_unsafe(expr.span, AccessToUnionField); @@ -536,7 +530,6 @@ enum UnsafeOpKind { UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, - AssignToDroppingUnionField, AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, @@ -554,7 +547,6 @@ impl UnsafeOpKind { UseOfMutableStatic => "use of mutable static", UseOfExternStatic => "use of extern static", DerefOfRawPointer => "dereference of raw pointer", - AssignToDroppingUnionField => "assignment to union field that might need dropping", AccessToUnionField => "access to union field", MutationOfLayoutConstrainedField => "mutation of layout constrained field", BorrowOfLayoutConstrainedField => { @@ -599,11 +591,6 @@ impl UnsafeOpKind { "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), - AssignToDroppingUnionField => ( - Cow::Borrowed(self.simple_description()), - "the previous content of the field will be dropped, which causes undefined \ - behavior if the field was not properly initialized", - ), AccessToUnionField => ( Cow::Borrowed(self.simple_description()), "the field may not be properly initialized: using uninitialized data will cause \ @@ -631,7 +618,7 @@ impl UnsafeOpKind { pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) { // THIR unsafeck is gated under `-Z thir-unsafeck` - if !tcx.sess.opts.debugging_opts.thir_unsafeck { + if !tcx.sess.opts.unstable_opts.thir_unsafeck { return; } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 11cd2a9aa4dea..a7d8431b6c7a2 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -5,7 +5,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(min_specialization)] #![feature(once_cell)] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 5470cc1262e84..d21a8c4f9b9a3 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -2,7 +2,7 @@ use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; use rustc_hir::intravisit::FnKind; -use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind}; +use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt}; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; @@ -30,7 +30,9 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { }; let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_substs }; - if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) { + if let Some(NonRecursive) = + TriColorDepthFirstSearch::new(&body.basic_blocks).run_from_start(&mut vis) + { return; } if vis.reachable_recursive_calls.is_empty() { @@ -101,7 +103,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> { } } -impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { +impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> { type BreakVal = NonRecursive; fn node_examined( diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 59750d5d0b88e..dccaa61ed89d4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -74,6 +74,8 @@ impl<'tcx> Cx<'tcx> { )), }; + let else_block = local.els.map(|els| self.mirror_block(els)); + let mut pattern = self.pattern_from_hir(local.pat); debug!(?pattern); @@ -110,6 +112,7 @@ impl<'tcx> Cx<'tcx> { }, pattern, initializer: local.init.map(|init| self.mirror_expr(init)), + else_block, lint_level: LintLevel::Explicit(local.hir_id), }, opt_destruction_scope: opt_dxn_ext, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b5f3cd828a03e..05da33caa91bd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,3 +1,4 @@ +use crate::thir::cx::region::Scope; use crate::thir::cx::Cx; use crate::thir::util::UserAnnotatedTyHelpers; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -31,13 +32,14 @@ impl<'tcx> Cx<'tcx> { exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() } + #[instrument(level = "trace", skip(self, hir_expr))] pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { let temp_lifetime = self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id); let expr_scope = region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }; - debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span); + trace!(?hir_expr.hir_id, ?hir_expr.span); let mut expr = self.make_mirror_unadjusted(hir_expr); @@ -46,14 +48,18 @@ impl<'tcx> Cx<'tcx> { _ => None, }; + trace!(?expr.ty); + // Now apply adjustments, if any. for adjustment in self.typeck_results.expr_adjustments(hir_expr) { - debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment); + trace!(?expr, ?adjustment); let span = expr.span; expr = self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); } + trace!(?expr.ty, "after adjustments"); + // Next, wrap this up in the expr's scope. expr = Expr { temp_lifetime, @@ -158,6 +164,98 @@ impl<'tcx> Cx<'tcx> { Expr { temp_lifetime, ty: adjustment.target, span, kind } } + /// Lowers a cast expression. + /// + /// Dealing with user type annotations is left to the caller. + fn mirror_expr_cast( + &mut self, + source: &'tcx hir::Expr<'tcx>, + temp_lifetime: Option<Scope>, + span: Span, + ) -> ExprKind<'tcx> { + let tcx = self.tcx; + + // Check to see if this cast is a "coercion cast", where the cast is actually done + // using a coercion (or is a no-op). + 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() { + // Special cased so that we can type check that the element + // type of the source matches the pointed to type of the + // destination. + ExprKind::Pointer { + source: self.mirror_expr(source), + cast: PointerCast::ArrayToPointer, + } + } else { + // check whether this is casting an enum variant discriminant + // to prevent cycles, we refer to the discriminant initializer + // which is always an integer and thus doesn't need to know the + // enum's layout (or its tag type) to compute it during const eval + // Example: + // enum Foo { + // A, + // B = A as isize + 4, + // } + // The correct solution would be to add symbolic computations to miri, + // so we wouldn't have to compute and store the actual value + + let hir::ExprKind::Path(ref qpath) = source.kind else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + + let res = self.typeck_results().qpath_res(qpath, source.hir_id); + let ty = self.typeck_results().node_type(source.hir_id); + let ty::Adt(adt_def, substs) = ty.kind() else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + + let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + + let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); + let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx); + + use rustc_middle::ty::util::IntTypeExt; + let ty = adt_def.repr().discr_type(); + let discr_ty = ty.to_ty(tcx); + + let param_env_ty = self.param_env.and(discr_ty); + let size = tcx + .layout_of(param_env_ty) + .unwrap_or_else(|e| { + panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) + }) + .size; + + let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap(); + let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; + let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); + + let source = match discr_did { + // in case we are offsetting from a computed discriminant + // and not the beginning of discriminants (which is always `0`) + Some(did) => { + let kind = ExprKind::NamedConst { def_id: did, substs, user_ty: None }; + let lhs = + self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); + let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; + self.thir.exprs.push(Expr { + temp_lifetime, + ty: discr_ty, + span: span, + kind: bin, + }) + } + None => offset, + }; + + ExprKind::Cast { source } + } + } + fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); @@ -604,98 +702,7 @@ impl<'tcx> Cx<'tcx> { expr, cast_ty.hir_id, user_ty, ); - // Check to see if this cast is a "coercion cast", where the cast is actually done - // using a coercion (or is a no-op). - let cast = 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() { - // Special cased so that we can type check that the element - // type of the source matches the pointed to type of the - // destination. - ExprKind::Pointer { - source: self.mirror_expr(source), - cast: PointerCast::ArrayToPointer, - } - } else { - // check whether this is casting an enum variant discriminant - // to prevent cycles, we refer to the discriminant initializer - // which is always an integer and thus doesn't need to know the - // enum's layout (or its tag type) to compute it during const eval - // Example: - // enum Foo { - // A, - // B = A as isize + 4, - // } - // The correct solution would be to add symbolic computations to miri, - // so we wouldn't have to compute and store the actual value - let var = if let hir::ExprKind::Path(ref qpath) = source.kind { - let res = self.typeck_results().qpath_res(qpath, source.hir_id); - self.typeck_results().node_type(source.hir_id).ty_adt_def().and_then( - |adt_def| match res { - Res::Def( - DefKind::Ctor(CtorOf::Variant, CtorKind::Const), - variant_ctor_id, - ) => { - let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); - let (d, o) = adt_def.discriminant_def_for_variant(idx); - use rustc_middle::ty::util::IntTypeExt; - let ty = adt_def.repr().discr_type(); - let ty = ty.to_ty(tcx); - Some((d, o, ty)) - } - _ => None, - }, - ) - } else { - None - }; - - let source = if let Some((did, offset, var_ty)) = var { - let param_env_ty = self.param_env.and(var_ty); - let size = tcx - .layout_of(param_env_ty) - .unwrap_or_else(|e| { - panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) - }) - .size; - let lit = ScalarInt::try_from_uint(offset as u128, size).unwrap(); - let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; - let offset = self.thir.exprs.push(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind, - }); - match did { - Some(did) => { - // in case we are offsetting from a computed discriminant - // and not the beginning of discriminants (which is always `0`) - let substs = InternalSubsts::identity_for_item(tcx, did); - let kind = - ExprKind::NamedConst { def_id: did, substs, user_ty: None }; - let lhs = self.thir.exprs.push(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind, - }); - let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; - self.thir.exprs.push(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind: bin, - }) - } - None => offset, - } - } else { - self.mirror_expr(source) - }; - - ExprKind::Cast { source: source } - }; + let cast = self.mirror_expr_cast(*source, temp_lifetime, expr.span); if let Some(user_ty) = user_ty { // NOTE: Creating a new Expr and wrapping a Cast inside of it may be @@ -796,7 +803,7 @@ impl<'tcx> Cx<'tcx> { } }; let ty = self.tcx().mk_fn_def(def_id, substs); - Expr { temp_lifetime, ty, span, kind: ExprKind::zero_sized_literal(user_ty) } + Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } } } fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { @@ -825,7 +832,7 @@ impl<'tcx> Cx<'tcx> { | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(_) => { let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); - ExprKind::zero_sized_literal(user_ty) + ExprKind::ZstLiteral { user_ty } } Res::Def(DefKind::ConstParam, def_id) => { diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index d853a5e9ee797..35a0afd6813a8 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -5,7 +5,6 @@ use crate::thir::pattern::pat_from_hir; use crate::thir::util::UserAnnotatedTyHelpers; -use rustc_ast as ast; use rustc_data_structures::steal::Steal; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -13,10 +12,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; -use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; -use rustc_middle::mir::ConstantKind; use rustc_middle::thir::*; -use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt}; +use rustc_middle::ty::{self, RvalueScopes, TyCtxt}; use rustc_span::Span; pub(crate) fn thir_body<'tcx>( @@ -80,28 +77,10 @@ impl<'tcx> Cx<'tcx> { } } - #[instrument(skip(self), level = "debug")] - pub(crate) fn const_eval_literal( - &mut self, - lit: &'tcx ast::LitKind, - ty: Ty<'tcx>, - sp: Span, - neg: bool, - ) -> ConstantKind<'tcx> { - match self.tcx.at(sp).lit_to_mir_constant(LitToConstInput { lit, ty, neg }) { - Ok(c) => c, - Err(LitToConstError::Reported) => { - // create a dummy value and continue compiling - ConstantKind::Ty(self.tcx.const_error(ty)) - } - Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"), - } - } - #[tracing::instrument(level = "debug", skip(self))] pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> { let p = match self.tcx.hir().get(p.hir_id) { - Node::Pat(p) | Node::Binding(p) => p, + Node::Pat(p) => p, node => bug!("pattern became {:?}", node), }; pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 76333b755b747..5bd1fad0bcb9f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span}; +use rustc_span::{BytePos, Span}; pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { @@ -77,6 +77,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { intravisit::walk_local(self, loc); + let els = loc.els; + if let Some(init) = loc.init && els.is_some() { + self.check_let(&loc.pat, init, loc.span); + } let (msg, sp) = match loc.source { hir::LocalSource::Normal => ("local binding", Some(loc.span)), @@ -84,7 +88,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { hir::LocalSource::AwaitDesugar => ("`await` future binding", None), hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), }; - self.check_irrefutable(&loc.pat, msg, sp); + if els.is_none() { + self.check_irrefutable(&loc.pat, msg, sp); + } } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { @@ -432,7 +438,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ an `enum` with only one variant", ); - if self.tcx.sess.source_map().span_to_snippet(span).is_ok() { + if self.tcx.sess.source_map().is_span_accessible(span) { let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1)); let start_span = span.shrink_to_lo(); let end_span = semi_span.shrink_to_lo(); @@ -947,7 +953,7 @@ fn adt_defined_here<'p, 'tcx>( span.push_span_label(def_span, String::new()); for pat in spans { - span.push_span_label(pat, "not covered".to_string()); + span.push_span_label(pat, "not covered"); } err.span_note(span, &format!("`{}` defined here", ty)); } @@ -1125,17 +1131,16 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L }) if Some(*hir_id) == pat_id => { return LetSource::IfLetGuard; } - hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => { - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind { - return LetSource::LetElse(expn_data.call_site); - } - } _ => {} } let parent_parent = hir.get_parent_node(parent); let parent_parent_node = hir.get(parent_parent); + if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) = + parent_parent_node + { + return LetSource::LetElse(*span); + } let parent_parent_parent = hir.get_parent_node(parent_parent); let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent); 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 845be2ab264a6..e32e0b11ba497 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 @@ -120,32 +120,37 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> { - traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { - with_no_trimmed_paths!(match non_sm_ty.kind { - traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), - traits::NonStructuralMatchTyKind::Dynamic => { - "trait objects cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Opaque => { - "opaque types cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Closure => { - "closures cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Generator => { - "generators cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTyKind::Param => { - bug!("use of a constant whose type is a parameter inside a pattern") - } - traits::NonStructuralMatchTyKind::Projection => { - bug!("use of a constant whose type is a projection inside a pattern") - } - traits::NonStructuralMatchTyKind::Foreign => { - bug!("use of a value of a foreign type inside a pattern") - } - }) - }) + traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map( + |non_sm_ty| { + with_no_trimmed_paths!(match non_sm_ty.kind { + traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTyKind::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Float => { + "floating-point numbers cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTyKind::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTyKind::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTyKind::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { @@ -550,7 +555,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { id, span, |lint| { - lint.build(&msg).emit(); + lint.build(msg).emit(); }, ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 60db98073a3b9..c0fd19cf71c31 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1202,35 +1202,32 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Creates a new list of wildcard fields for a given constructor. The result must have a /// length of `constructor.arity()`. - pub(super) fn wildcards( - cx: &MatchCheckCtxt<'p, 'tcx>, - ty: Ty<'tcx>, - constructor: &Constructor<'tcx>, - ) -> Self { + #[instrument(level = "trace")] + pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { let ret = match constructor { - Single | Variant(_) => match ty.kind() { - ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()), - ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)), + Single | Variant(_) => match pcx.ty.kind() { + ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)), ty::Adt(adt, substs) => { if adt.is_box() { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. - Fields::wildcards_from_tys(cx, once(substs.type_at(0))) + Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0))) } else { let variant = &adt.variant(constructor.variant_index_for_adt(*adt)); - let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant) + let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant) .map(|(_, ty)| ty); - Fields::wildcards_from_tys(cx, tys) + Fields::wildcards_from_tys(pcx.cx, tys) } } - _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), + _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx), }, - Slice(slice) => match *ty.kind() { + Slice(slice) => match *pcx.ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); - Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) + Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty)) } - _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), + _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx), }, Str(..) | FloatRange(..) @@ -1243,7 +1240,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { bug!("called `Fields::wildcards` on an `Or` ctor") } }; - debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); + debug!(?ret); ret } @@ -1286,7 +1283,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern /// `Some(_)`. pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { - let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor); + let fields = Fields::wildcards(pcx, &ctor); DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP) } @@ -1553,13 +1550,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { /// `other_ctor` can be different from `self.ctor`, but must be covered by it. pub(super) fn specialize<'a>( &'a self, - cx: &MatchCheckCtxt<'p, 'tcx>, + pcx: PatCtxt<'_, 'p, 'tcx>, other_ctor: &Constructor<'tcx>, ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> { match (&self.ctor, other_ctor) { (Wildcard, _) => { // We return a wildcard for each field of `other_ctor`. - Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect() + Fields::wildcards(pcx, other_ctor).iter_patterns().collect() } (Slice(self_slice), Slice(other_slice)) if self_slice.arity() != other_slice.arity() => @@ -1578,7 +1575,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let prefix = &self.fields.fields[..prefix]; let suffix = &self.fields.fields[self_slice.arity() - suffix..]; let wildcard: &_ = - cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); + pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); let extra_wildcards = other_slice.arity() - self_slice.arity(); let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); prefix.iter().chain(extra_wildcards).chain(suffix).collect() diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a13748a2d474a..7d22f7b69d862 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -196,6 +196,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { let mut ty = self.typeck_results.node_type(pat.hir_id); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9e7a267ecbd7f..f27ec22a8dee2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { /// This is roughly the inverse of `Constructor::apply`. fn pop_head_constructor( &self, - cx: &MatchCheckCtxt<'p, 'tcx>, + pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, ) -> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor); + let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor); new_fields.extend_from_slice(&self.pats[1..]); PatStack::from_vec(new_fields) } @@ -475,7 +475,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { let mut matrix = Matrix::empty(); for row in &self.patterns { if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx.cx, ctor); + let new_row = row.pop_head_constructor(pcx, ctor); matrix.push(new_row); } } @@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>( is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'p, 'tcx> { - debug!("matrix,v={:?}{:?}", matrix, v); + debug!(?matrix, ?v); let Matrix { patterns: rows, .. } = matrix; // The base case. We are pattern-matching on () and the return value is @@ -806,11 +806,6 @@ fn is_useful<'p, 'tcx>( debug_assert!(rows.iter().all(|r| r.len() == v.len())); - let ty = v.head().ty(); - let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); - debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); - let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; - // If the first pattern is an or-pattern, expand it. let mut ret = Usefulness::new_not_useful(witness_preference); if v.head().is_or_pat() { @@ -832,6 +827,19 @@ fn is_useful<'p, 'tcx>( } } } else { + let mut ty = v.head().ty(); + + // Opaque types can't get destructured/split, but the patterns can + // actually hint at hidden types, so we use the patterns' types instead. + if let ty::Opaque(..) = v.head().ty().kind() { + if let Some(row) = rows.first() { + ty = row.head().ty(); + } + } + let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); + debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); + let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; + let v_ctor = v.head().ctor(); debug!(?v_ctor); if let Constructor::IntRange(ctor_range) = &v_ctor { @@ -853,7 +861,7 @@ fn is_useful<'p, 'tcx>( debug!("specialize({:?})", ctor); // We cache the result of `Fields::wildcards` because it is used a lot. let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); - let v = v.pop_head_constructor(cx, &ctor); + let v = v.pop_head_constructor(pcx, &ctor); let usefulness = ensure_sufficient_stack(|| { is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false) }); diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index a0c70a3fd81f1..baf9735fbc846 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] polonius-engine = "0.13.0" regex = "1" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 05a4d7bbf3e6f..5c77f3ea39533 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -228,7 +228,7 @@ impl Direction for Backward { ) where A: Analysis<'tcx>, { - for pred in body.predecessors()[bb].iter().copied() { + for pred in body.basic_blocks.predecessors()[bb].iter().copied() { match body[pred].terminator().kind { // Apply terminator-specific edge effects. // @@ -316,7 +316,7 @@ where fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { assert!(!self.effects_applied); - let values = &self.body.switch_sources()[&(self.bb, self.pred)]; + let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)]; let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); let mut tmp = None; diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 20e14a77c1e57..f374658ceb691 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -101,7 +101,7 @@ where // transfer function for each block exactly once (assuming that we process blocks in RPO). // // In this case, there's no need to compute the block transfer functions ahead of time. - if !body.is_cfg_cyclic() { + if !body.basic_blocks.is_cfg_cyclic() { return Self::new(tcx, body, analysis, None); } @@ -289,7 +289,7 @@ where io::BufWriter::new(fs::File::create(&path)?) } - None if tcx.sess.opts.debugging_opts.dump_mir_dataflow + None if tcx.sess.opts.unstable_opts.dump_mir_dataflow && dump_enabled(tcx, A::NAME, def_id) => { create_dump_file( @@ -314,8 +314,8 @@ where let graphviz = graphviz::Formatter::new(body, results, style); let mut render_opts = - vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())]; - if tcx.sess.opts.debugging_opts.graphviz_dark_mode { + vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())]; + if tcx.sess.opts.unstable_opts.graphviz_dark_mode { render_opts.push(dot::RenderOption::DarkTheme); } dot::render_opts(&graphviz, &mut buf, &render_opts)?; diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index 9a462f6e1a41a..d6b89eb82275e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -199,14 +199,16 @@ impl<T: JoinSemiLattice> MeetSemiLattice for Dual<T> { } /// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no -/// value of `T` is comparable with any other. A flat set has the following [Hasse diagram]: +/// value of `T` is comparable with any other. +/// +/// A flat set has the following [Hasse diagram]: /// /// ```text -/// top -/// / / \ \ +/// top +/// / ... / / \ \ ... \ /// all possible values of `T` -/// \ \ / / -/// bottom +/// \ ... \ \ / / ... / +/// bottom /// ``` /// /// [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 67c16e6c0849d..f9fd6c9c56b42 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -1,7 +1,7 @@ //! A framework that can express both [gen-kill] and generic dataflow problems. //! -//! To actually use this framework, you must implement either the `Analysis` or the -//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill +//! To use this framework, implement either the [`Analysis`] or the +//! [`GenKillAnalysis`] trait. If your transfer function can be expressed with only gen/kill //! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The //! `impls` module contains several examples of gen/kill dataflow analyses. //! @@ -96,7 +96,7 @@ impl<T: Idx> BitSetExt<T> for ChunkedBitSet<T> { } } -/// Define the domain of a dataflow problem. +/// Defines the domain of a dataflow problem. /// /// This trait specifies the lattice on which this analysis operates (the domain) as well as its /// initial value at the entry point of each basic block. @@ -113,12 +113,12 @@ pub trait AnalysisDomain<'tcx> { /// suitable as part of a filename. const NAME: &'static str; - /// The initial value of the dataflow state upon entry to each basic block. + /// Returns the initial value of the dataflow state upon entry to each basic block. fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; /// Mutates the initial value of the dataflow state upon entry to the `START_BLOCK`. /// - /// For backward analyses, initial state besides the bottom value is not yet supported. Trying + /// For backward analyses, initial state (besides the bottom value) is not yet supported. Trying /// to mutate the initial state will result in a panic. // // FIXME: For backward dataflow analyses, the initial state should be applied to every basic @@ -155,9 +155,9 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with an effect that occurs immediately *before* the /// given statement. /// - /// This method is useful if the consumer of the results of this analysis needs only to observe + /// This method is useful if the consumer of the results of this analysis only needs to observe /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without implementing `apply_statement_effect`. + /// analyses should not implement this without also implementing `apply_statement_effect`. fn apply_before_statement_effect( &self, _state: &mut Self::Domain, @@ -184,7 +184,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// /// This method is useful if the consumer of the results of this analysis needs only to observe /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without implementing `apply_terminator_effect`. + /// analyses should not implement this without also implementing `apply_terminator_effect`. fn apply_before_terminator_effect( &self, _state: &mut Self::Domain, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 627fe3f7f576b..0f8e86d1d6679 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -102,7 +102,8 @@ where | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) - | mir::Rvalue::Aggregate(..) => {} + | mir::Rvalue::Aggregate(..) + | mir::Rvalue::CopyForDeref(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs index 584ab9718ed65..83ce4c44b7144 100644 --- a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs @@ -81,7 +81,7 @@ where // deinitialized, although clearly it is only partially deinitialized. This analysis is not // actually used anywhere at the moment, so this is not critical, but this does need to be fixed // before it starts being used again. - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext}; match context { // These are handled specially in `call_return_effect` and `yield_resume_effect`. diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 35febb5d33060..e64136928cce8 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -111,7 +111,7 @@ where } } - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { // Because we do not call `super_place` above, `visit_local` is only called for locals that // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use // of the return place in a `Return` terminator or the index in an `Index` projection. diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index af6a1bb1545ea..fd1e492779f1b 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -317,7 +317,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { Self::update_bits(trans, path, s) }); - if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { return; } @@ -340,7 +340,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { Self::update_bits(trans, path, s) }); - if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { return; } @@ -379,7 +379,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { discr: &mir::Operand<'tcx>, edge_effects: &mut impl SwitchIntEdgeEffects<G>, ) { - if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { return; } @@ -495,7 +495,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { discr: &mir::Operand<'tcx>, edge_effects: &mut impl SwitchIntEdgeEffects<G>, ) { - if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration { + if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { return; } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 33d2941814729..f6b5af90a85c8 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -153,7 +153,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc _: &mir::Statement<'tcx>, loc: Location, ) { - // If we move from a place then only stops needing storage *after* + // If we move from a place then it only stops needing storage *after* // that statement. self.check_for_move(trans, loc); } @@ -288,12 +288,12 @@ impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> where T: GenKill<Local>, { - fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { let mut borrowed_locals = self.borrowed_locals.borrow_mut(); borrowed_locals.seek_before_primary_effect(loc); - if !borrowed_locals.contains(*local) { - self.trans.kill(*local); + if !borrowed_locals.contains(local) { + self.trans.kill(local); } } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index e4c130f0807dd..5793a286bd03d 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -38,6 +38,7 @@ pub mod impls; pub mod move_paths; pub mod rustc_peek; pub mod storage; +pub mod un_derefer; pub(crate) mod indexes { pub(crate) use super::move_paths::MovePathIndex; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index 28936274baafa..7806e8f45d3ad 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -48,6 +48,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> { match *self { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()), + ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()), ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), ProjectionElem::Subslice { from, to, from_end } => { ProjectionElem::Subslice { from, to, from_end } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index b08cb50f77aed..19aa71d7bc772 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -1,3 +1,4 @@ +use crate::un_derefer::UnDerefer; use rustc_index::vec::IndexVec; use rustc_middle::mir::tcx::RvalueInitializationState; use rustc_middle::mir::*; @@ -19,6 +20,7 @@ struct MoveDataBuilder<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, data: MoveData<'tcx>, errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, + un_derefer: UnDerefer<'tcx>, } impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { @@ -32,6 +34,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { tcx, param_env, errors: Vec::new(), + un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() }, data: MoveData { moves: IndexVec::new(), loc_map: LocationMap::new(body), @@ -94,6 +97,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// /// Maybe we should have separate "borrowck" and "moveck" modes. fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> { + if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body) + { + return self.move_path_for(new_place); + } + debug!("lookup({:?})", place); let mut base = self.builder.data.rev_lookup.locals[place.local]; @@ -276,6 +284,12 @@ struct Gatherer<'b, 'a, 'tcx> { impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match &stmt.kind { + StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => { + assert!(place.projection.is_empty()); + if self.builder.body.local_decls[place.local].is_deref_temp() { + self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed); + } + } StatementKind::Assign(box (place, rval)) => { self.create_move_path(*place); if let RvalueInitializationState::Shallow = rval.initialization_state() { @@ -294,7 +308,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } StatementKind::StorageLive(_) => {} StatementKind::StorageDead(local) => { - self.gather_move(Place::from(*local)); + // DerefTemp locals (results of CopyForDeref) don't actually move anything. + if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) { + self.gather_move(Place::from(*local)); + } } StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => { span_bug!( @@ -328,6 +345,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.gather_operand(operand); } } + Rvalue::CopyForDeref(..) => unreachable!(), Rvalue::Ref(..) | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) @@ -439,6 +457,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_move(&mut self, place: Place<'tcx>) { debug!("gather_move({:?}, {:?})", self.loc, place); + if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body) + { + self.gather_move(new_place); + return; + } if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] = **place.projection @@ -494,6 +517,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { debug!("gather_init({:?}, {:?})", self.loc, place); + if let Some(new_place) = self.builder.un_derefer.derefer(place, self.builder.body) { + self.gather_init(new_place.as_ref(), kind); + return; + } + let mut place = place; // Check if we are assigning into a field of a union, if so, lookup the place diff --git a/compiler/rustc_mir_dataflow/src/storage.rs b/compiler/rustc_mir_dataflow/src/storage.rs index 4a354c4c65b08..c909648ea017e 100644 --- a/compiler/rustc_mir_dataflow/src/storage.rs +++ b/compiler/rustc_mir_dataflow/src/storage.rs @@ -4,10 +4,7 @@ use rustc_middle::mir::{self, Local}; /// The set of locals in a MIR body that do not have `StorageLive`/`StorageDead` annotations. /// /// These locals have fixed storage for the duration of the body. -// -// FIXME: Currently, we need to traverse the entire MIR to compute this. We should instead store it -// as a field in the `LocalDecl` for each `Local`. -pub fn always_live_locals(body: &mir::Body<'_>) -> BitSet<Local> { +pub fn always_storage_live_locals(body: &mir::Body<'_>) -> BitSet<Local> { let mut always_live_locals = BitSet::new_filled(body.local_decls.len()); for block in body.basic_blocks() { diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs new file mode 100644 index 0000000000000..ec2e516f7ac5f --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -0,0 +1,36 @@ +use rustc_data_structures::stable_map::FxHashMap; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +/// Used for reverting changes made by `DerefSeparator` +pub struct UnDerefer<'tcx> { + pub tcx: TyCtxt<'tcx>, + pub derefer_sidetable: FxHashMap<Local, Place<'tcx>>, +} + +impl<'tcx> UnDerefer<'tcx> { + pub fn derefer(&self, place: PlaceRef<'tcx>, body: &Body<'tcx>) -> Option<Place<'tcx>> { + let reffed = self.derefer_sidetable.get(&place.local)?; + + let new_place = reffed.project_deeper(place.projection, self.tcx); + if body.local_decls[new_place.local].is_deref_temp() { + return self.derefer(new_place.as_ref(), body); + } + Some(new_place) + } + + pub fn ref_finder(&mut self, body: &Body<'tcx>) { + for (_bb, data) in body.basic_blocks().iter_enumerated() { + for stmt in data.statements.iter() { + match stmt.kind { + StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => { + if body.local_decls[place.local].is_deref_temp() { + self.derefer_sidetable.insert(place.local, reffed); + } + } + _ => (), + } + } + } + } +} diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 8a8098e9ab996..85b7a4af59894 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -8,7 +8,7 @@ doctest = false [dependencies] itertools = "0.10.1" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 11980382ffdb2..2502e8b603c3e 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -1,6 +1,5 @@ use crate::MirPass; use rustc_ast::InlineAsmOptions; -use rustc_hir::def::DefKind; use rustc_middle::mir::*; use rustc_middle::ty::layout; use rustc_middle::ty::{self, TyCtxt}; @@ -31,11 +30,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { // We don't simplify the MIR of constants at this time because that // namely results in a cyclic query when we call `tcx.type_of` below. - let is_function = match kind { - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure(def_id), - }; - if !is_function { + if !kind.is_fn_like() { return; } @@ -80,7 +75,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) } TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => { - tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind + tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Unwind && layout::fn_can_unwind(tcx, None, Abi::Rust) } TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => { diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index 10d522717344d..f12c8560c0e82 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -39,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards { impl AddCallGuards { pub fn add_call_guards(&self, body: &mut Body<'_>) { let mut pred_count: IndexVec<_, _> = - body.predecessors().iter().map(|ps| ps.len()).collect(); + body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect(); pred_count[START_BLOCK] += 1; // We need a place to store the new blocks generated diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 0495439385bee..86327ade94b8a 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -28,13 +28,15 @@ fn is_stable(place: PlaceRef<'_>) -> bool { ProjectionElem::Field { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | + ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast { .. } => true, } }) } -/// Determine whether this type may be a reference (or box), and thus needs retagging. -fn may_be_reference(ty: Ty<'_>) -> bool { +/// Determine whether this type may contain a reference (or box), and thus needs retagging. +/// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this. +fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> bool { match ty.kind() { // Primitive types that are not references ty::Bool @@ -50,27 +52,28 @@ fn may_be_reference(ty: Ty<'_>) -> bool { // References ty::Ref(..) => true, ty::Adt(..) if ty.is_box() => true, - // Compound types are not references - ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..) => false, + // Compound types: recurse + ty::Array(ty, _) | ty::Slice(ty) => { + // This does not branch so we keep the depth the same. + may_contain_reference(*ty, depth, tcx) + } + ty::Tuple(tys) => { + depth == 0 || tys.iter().any(|ty| may_contain_reference(ty, depth - 1, tcx)) + } + ty::Adt(adt, subst) => { + depth == 0 + || adt.variants().iter().any(|v| { + v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, subst), depth - 1, tcx)) + }) + } // Conservative fallback _ => true, } } -/// Determines whether or not this LocalDecl is temp, if not it needs retagging. -fn is_not_temp<'tcx>(local_decl: &LocalDecl<'tcx>) -> bool { - if let Some(local_info) = &local_decl.local_info { - match local_info.as_ref() { - LocalInfo::DerefTemp => return false, - _ => (), - }; - } - return true; -} - impl<'tcx> MirPass<'tcx> for AddRetag { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.opts.debugging_opts.mir_emit_retag + sess.opts.unstable_opts.mir_emit_retag } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -78,13 +81,14 @@ impl<'tcx> MirPass<'tcx> for AddRetag { super::add_call_guards::AllCallEdges.run_pass(tcx, body); let (span, arg_count) = (body.span, body.arg_count); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let basic_blocks = body.basic_blocks.as_mut(); + let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. is_stable(place.as_ref()) - && may_be_reference(place.ty(&*local_decls, tcx).ty) - && is_not_temp(&local_decls[place.local]) + && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx) + && !local_decls[place.local].is_deref_temp() }; let place_base_raw = |place: &Place<'tcx>| { // If this is a `Deref`, get the type of what we are deref'ing. 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 097a6186cd57a..8838b14c53a58 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -1,5 +1,4 @@ -use rustc_errors::DiagnosticBuilder; -use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, LintDiagnosticBuilder}; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 4bf66cd4c9f2e..2eb38941f1a50 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -39,13 +39,11 @@ fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { let message = if tcx.generics_of(def_id).own_requires_monomorphization() { "`#[derive]` can't be used on a `#[repr(packed)]` struct with \ type or const parameters (error E0133)" - .to_string() } else { "`#[derive]` can't be used on a `#[repr(packed)]` struct that \ does not derive Copy (error E0133)" - .to_string() }; - lint.build(&message).emit(); + lint.build(message).emit(); }); } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 1f73b7da815c5..ded1f0462cb01 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -219,22 +219,15 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // We have to check the actual type of the assignment, as that determines if the // old value is being dropped. let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. - let manually_drop = assigned_ty - .ty_adt_def() - .map_or(false, |adt_def| adt_def.is_manually_drop()); - let nodrop = manually_drop - || assigned_ty.is_copy_modulo_regions( - self.tcx.at(self.source_info.span), - self.param_env, + if assigned_ty.needs_drop( + self.tcx, + self.tcx.param_env(base_ty.ty_adt_def().unwrap().did()), + ) { + // This would be unsafe, but should be outright impossible since we reject such unions. + self.tcx.sess.delay_span_bug( + self.source_info.span, + "union fields that need dropping should be impossible", ); - if !nodrop { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::AssignToDroppingUnionField, - ); - } else { - // write to non-drop union field, safe } } else { self.require_unsafe( diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index 8944ebed9a704..6f0ae4f07ab79 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -16,7 +16,7 @@ pub struct ConstDebugInfo; impl<'tcx> MirPass<'tcx> for ConstDebugInfo { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0 + sess.opts.unstable_opts.unsound_mir_opts && sess.mir_opt_level() > 0 } fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -88,12 +88,12 @@ fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Consta } impl Visitor<'_> for LocalUseVisitor { - fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { if context.is_mutating_use() { - self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1); + self.local_mutating_uses[local] = self.local_mutating_uses[local].saturating_add(1); if context.is_place_assignment() { - self.local_assignment_locations[*local] = Some(location); + self.local_assignment_locations[local] = Some(location); } } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 412a5b4fc9104..acd9e60535378 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -19,19 +19,18 @@ use rustc_middle::mir::{ use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{ - self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable, + self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable, }; use rustc_span::{def_id::DefId, Span}; -use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use rustc_target::spec::abi::Abi; +use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout}; +use rustc_target::spec::abi::Abi as CallAbi; use rustc_trait_selection::traits; use crate::MirPass; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame, - ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy, - Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, - StackPopUnwind, + ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, + Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -60,11 +59,8 @@ macro_rules! throw_machine_stop_str { pub struct ConstProp; impl<'tcx> MirPass<'tcx> for ConstProp { - fn is_enabled(&self, _sess: &rustc_session::Session) -> bool { - // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it - // runs even when MIR optimizations are disabled. We should separate the lint out from the - // transform and move the lint as early in the pipeline as possible. - true + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 1 } #[instrument(skip(self, tcx), level = "debug")] @@ -199,7 +195,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> fn find_mir_or_eval_fn( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, - _abi: Abi, + _abi: CallAbi, _args: &[OpTy<'tcx>], _destination: &PlaceTy<'tcx>, _target: Option<BasicBlock>, @@ -237,15 +233,19 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + fn access_local<'a>( + frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: Local, - ) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> { let l = &frame.locals[local]; - if l.value == LocalValue::Unallocated { - throw_machine_stop_str!("tried to access an unallocated local") + if matches!( + l.value, + LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)) + ) { + // For us "uninit" means "we don't know its value, might be initiailized or not". + // So stop here. + throw_machine_stop_str!("tried to access alocal with unknown value ") } l.access() @@ -255,8 +255,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: Local, - ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>> - { + ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> { if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") } @@ -391,7 +390,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) .ok() // Don't bother allocating memory for large values. - .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)) + // I don't know how return types can seem to be unsized but this happens in the + // `type/type-unsatisfiable.rs` test. + .filter(|ret_layout| { + !ret_layout.is_unsized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) + }) .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap()); let ret = ecx @@ -436,8 +439,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Remove `local` from the pool of `Locals`. Allows writing to them, /// but not reading from them anymore. fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { - ecx.frame_mut().locals[local] = - LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) }; + ecx.frame_mut().locals[local] = LocalState { + value: LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)), + layout: Cell::new(None), + }; } fn use_ecx<F, T>(&mut self, f: F) -> Option<T> @@ -616,6 +621,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // There's no other checking to do at this time. Rvalue::Aggregate(..) | Rvalue::Use(..) + | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) | Rvalue::Len(..) | Rvalue::Cast(..) @@ -654,6 +660,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), }; + if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) { + // We cannot handle Scalar Pair stuff. + return this.ecx.eval_rvalue_into_place(rvalue, place); + } + let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?; let dest = this.ecx.eval_place(place)?; @@ -786,12 +797,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Returns `true` if and only if this `op` should be const-propagated into. fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool { - let mir_opt_level = self.tcx.sess.mir_opt_level(); - - if mir_opt_level == 0 { - return false; - } - if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) { return false; } @@ -882,7 +887,7 @@ impl CanConstProp { } impl Visitor<'_> for CanConstProp { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { use rustc_middle::mir::visit::PlaceContext::*; match context { // Projections are fine, because `&mut foo.x` will be caught by @@ -1042,7 +1047,9 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { let frame = self.ecx.frame_mut(); frame.locals[local].value = if let StatementKind::StorageLive(_) = statement.kind { - LocalValue::Unallocated + LocalValue::Live(interpret::Operand::Immediate( + interpret::Immediate::Uninit, + )) } else { LocalValue::Dead }; diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 15ad13009e59a..49db140c4742e 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -18,20 +18,21 @@ use rustc_middle::mir::{ use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{ - self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, + self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, + TypeVisitable, }; use rustc_session::lint; use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use rustc_target::spec::abi::Abi; +use rustc_target::spec::abi::Abi as CallAbi; use rustc_trait_selection::traits; use crate::MirLint; use rustc_const_eval::const_eval::ConstEvalErr; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - LocalState, LocalValue, MemPlace, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, - Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, + LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, + StackPopCleanup, StackPopUnwind, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -190,7 +191,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> fn find_mir_or_eval_fn( _ecx: &mut InterpCx<'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, - _abi: Abi, + _abi: CallAbi, _args: &[OpTy<'tcx>], _destination: &PlaceTy<'tcx>, _target: Option<BasicBlock>, @@ -228,15 +229,19 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn access_local( - _ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + fn access_local<'a>( + frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, local: Local, - ) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> { + ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> { let l = &frame.locals[local]; - if l.value == LocalValue::Unallocated { - throw_machine_stop_str!("tried to access an uninitialized local") + if matches!( + l.value, + LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)) + ) { + // For us "uninit" means "we don't know its value, might be initiailized or not". + // So stop here. + throw_machine_stop_str!("tried to access a local with unknown value") } l.access() @@ -246,8 +251,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, local: Local, - ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>> - { + ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> { if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation { throw_machine_stop_str!("tried to write to a local that is marked as not propagatable") } @@ -383,7 +387,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) .ok() // Don't bother allocating memory for large values. - .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)) + // I don't know how return types can seem to be unsized but this happens in the + // `type/type-unsatisfiable.rs` test. + .filter(|ret_layout| { + !ret_layout.is_unsized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) + }) .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap()); let ret = ecx @@ -429,8 +437,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// Remove `local` from the pool of `Locals`. Allows writing to them, /// but not reading from them anymore. fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) { - ecx.frame_mut().locals[local] = - LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) }; + ecx.frame_mut().locals[local] = LocalState { + value: LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)), + layout: Cell::new(None), + }; } fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> { @@ -683,6 +693,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // There's no other checking to do at this time. Rvalue::Aggregate(..) | Rvalue::Use(..) + | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) | Rvalue::Len(..) | Rvalue::Cast(..) @@ -773,7 +784,7 @@ impl CanConstProp { } impl Visitor<'_> for CanConstProp { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { use rustc_middle::mir::visit::PlaceContext::*; match context { // Projections are fine, because `&mut foo.x` will be caught by @@ -914,7 +925,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { let frame = self.ecx.frame_mut(); frame.locals[local].value = if let StatementKind::StorageLive(_) = statement.kind { - LocalValue::Unallocated + LocalValue::Live(interpret::Operand::Immediate( + interpret::Immediate::Uninit, + )) } else { LocalValue::Dead }; diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 510f1e64ed1c0..759ea7cd32820 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -80,7 +80,7 @@ impl CoverageGraph { IndexVec<BasicCoverageBlock, BasicCoverageBlockData>, IndexVec<BasicBlock, Option<BasicCoverageBlock>>, ) { - let num_basic_blocks = mir_body.num_nodes(); + let num_basic_blocks = mir_body.basic_blocks.len(); let mut bcbs = IndexVec::with_capacity(num_basic_blocks); let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks); @@ -95,7 +95,7 @@ impl CoverageGraph { let mut basic_blocks = Vec::new(); for (bb, data) in mir_cfg_without_unwind { if let Some(last) = basic_blocks.last() { - let predecessors = &mir_body.predecessors()[bb]; + let predecessors = &mir_body.basic_blocks.predecessors()[bb]; if predecessors.len() > 1 || !predecessors.contains(last) { // The `bb` has more than one _incoming_ edge, and should start its own // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 782b620e28fe0..2619626a5675f 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -15,7 +15,6 @@ use spans::{CoverageSpan, CoverageSpans}; use crate::MirPass; use rustc_data_structures::graph::WithNumNodes; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_index::vec::IndexVec; use rustc_middle::hir; @@ -161,8 +160,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let mut debug_used_expressions = debug::UsedExpressions::new(); let dump_mir = dump_enabled(tcx, self.pass_name, def_id); - let dump_graphviz = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_graphviz; - let dump_spanview = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_spanview.is_some(); + let dump_graphviz = dump_mir && tcx.sess.opts.unstable_opts.dump_mir_graphviz; + let dump_spanview = dump_mir && tcx.sess.opts.unstable_opts.dump_mir_spanview.is_some(); if dump_graphviz { graphviz_data.enable(); @@ -576,12 +575,6 @@ fn get_body_span<'tcx>( fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { // FIXME(cjgillot) Stop hashing HIR manually here. - let mut hcx = tcx.create_no_span_stable_hashing_context(); - let mut stable_hasher = StableHasher::new(); let owner = hir_body.id().hir_id.owner; - let bodies = &tcx.hir_owner_nodes(owner).unwrap().bodies; - hcx.with_hir_bodies(false, owner, bodies, |hcx| { - hir_body.value.hash_stable(hcx, &mut stable_hasher) - }); - stable_hasher.finish() + tcx.hir_owner_nodes(owner).unwrap().hash_including_bodies.to_smaller_hash() } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 82070b903256c..423e78317aadb 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -321,7 +321,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> { - let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2); + let mut initial_spans = + Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks.len() * 2); for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data)); } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 213bb6608e139..6380f03528ae8 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -222,6 +222,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { bb, debug::term_type(&data.terminator().kind), mir_body + .basic_blocks .successors(bb) .map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) .join("\n") diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 28f3790914b38..9163672f57039 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -66,7 +66,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS return; } - let bbs = body.basic_blocks_mut(); + let bbs = body.basic_blocks.as_mut_preserves_cfg(); for Location { block, statement_index } in patch { bbs[block].statements[statement_index].make_nop(); } diff --git a/compiler/rustc_mir_transform/src/deaggregator.rs b/compiler/rustc_mir_transform/src/deaggregator.rs index 616ba819982ec..b93fe5879f4fd 100644 --- a/compiler/rustc_mir_transform/src/deaggregator.rs +++ b/compiler/rustc_mir_transform/src/deaggregator.rs @@ -11,8 +11,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let local_decls = &*local_decls; + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); for bb in basic_blocks { bb.expand_statements(|stmt| { // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL). @@ -37,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator { Some(expand_aggregate( lhs, operands.into_iter().map(|op| { - let ty = op.ty(local_decls, tcx); + let ty = op.ty(&body.local_decls, tcx); (op, ty) }), *kind, diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index bfb3ad1be2734..a00bb16f7ac67 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -35,6 +35,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { last_deref_idx = idx; } } + for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { let ty = p_ref.ty(&self.local_decls, self.tcx).ty; @@ -54,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { self.patcher.add_assign( loc, Place::from(temp), - Rvalue::Use(Operand::Move(deref_place)), + Rvalue::CopyForDeref(deref_place), ); place_local = temp; last_len = p_ref.projection.len(); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 84c7aada5e57f..33572068f5cd9 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -122,7 +122,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { // // Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove // storage statements at the moment). - sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 + sess.opts.unstable_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 33f201cbd2832..dba42f7aff033 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -95,7 +95,7 @@ pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 3 && sess.opts.debugging_opts.unsound_mir_opts + sess.mir_opt_level() >= 3 && sess.opts.unstable_opts.unsound_mir_opts } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index a80d2fbd644d4..44e3945d6fc89 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -110,13 +110,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { let patch = MirPatch::new(body); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + let local_decls = &mut body.local_decls; let mut visitor = ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; for (block, BasicBlockData { statements, terminator, .. }) in - basic_blocks.iter_enumerated_mut() + body.basic_blocks.as_mut().iter_enumerated_mut() { let mut index = 0; for statement in statements { diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index e0e27c53f1822..71ab6dee1b662 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -1,3 +1,4 @@ +use crate::deref_separator::deref_finder; use crate::MirPass; use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::BitSet; @@ -9,6 +10,7 @@ use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyl use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::on_lookup_result_bits; +use rustc_mir_dataflow::un_derefer::UnDerefer; use rustc_mir_dataflow::MoveDataParamEnv; use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; use rustc_mir_dataflow::{Analysis, ResultsCursor}; @@ -26,6 +28,8 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); + let mut un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: Default::default() }; + un_derefer.ref_finder(body); let def_id = body.source.def_id(); let param_env = tcx.param_env_reveal_all_normalized(def_id); let move_data = match MoveData::gather_moves(body, tcx, param_env) { @@ -41,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let elaborate_patch = { let body = &*body; let env = MoveDataParamEnv { move_data, param_env }; - let dead_unwinds = find_dead_unwinds(tcx, body, &env); + let dead_unwinds = find_dead_unwinds(tcx, body, &env, &un_derefer); let inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body) @@ -65,10 +69,12 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { init_data: InitializationData { inits, uninits }, drop_flags: Default::default(), patch: MirPatch::new(body), + un_derefer: un_derefer, } .elaborate() }; elaborate_patch.apply(body); + deref_finder(tcx, body); } } @@ -79,6 +85,7 @@ fn find_dead_unwinds<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, env: &MoveDataParamEnv<'tcx>, + und: &UnDerefer<'tcx>, ) -> BitSet<BasicBlock> { debug!("find_dead_unwinds({:?})", body.span); // We only need to do this pass once, because unwind edges can only @@ -92,7 +99,9 @@ fn find_dead_unwinds<'tcx>( for (bb, bb_data) in body.basic_blocks().iter_enumerated() { let place = match bb_data.terminator().kind { TerminatorKind::Drop { ref place, unwind: Some(_), .. } - | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place, + | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => { + und.derefer(place.as_ref(), body).unwrap_or(*place) + } _ => continue, }; @@ -256,6 +265,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> { init_data: InitializationData<'a, 'tcx>, drop_flags: FxHashMap<MovePathIndex, Local>, patch: MirPatch<'tcx>, + un_derefer: UnDerefer<'tcx>, } impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { @@ -298,7 +308,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let terminator = data.terminator(); let place = match terminator.kind { TerminatorKind::Drop { ref place, .. } - | TerminatorKind::DropAndReplace { ref place, .. } => place, + | TerminatorKind::DropAndReplace { ref place, .. } => { + self.un_derefer.derefer(place.as_ref(), self.body).unwrap_or(*place) + } _ => continue, }; @@ -312,12 +324,17 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { LookupResult::Parent(None) => continue, LookupResult::Parent(Some(parent)) => { let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); + + if self.body.local_decls[place.local].is_deref_temp() { + continue; + } + if maybe_dead { self.tcx.sess.delay_span_bug( terminator.source_info.span, &format!( "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", - bb, place, path, + bb, place, path ), ); } @@ -348,7 +365,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let resume_block = self.patch.resume_block(); match terminator.kind { - TerminatorKind::Drop { place, target, unwind } => { + TerminatorKind::Drop { mut place, target, unwind } => { + if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) { + place = new_place; + } + self.init_data.seek_before(loc); match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(path) => elaborate_drop( @@ -372,9 +393,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } } - TerminatorKind::DropAndReplace { place, ref value, target, unwind } => { + TerminatorKind::DropAndReplace { mut place, ref value, target, unwind } => { assert!(!data.is_cleanup); + if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) { + place = new_place; + } self.elaborate_replace(loc, place, value, target, unwind); } _ => continue, diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs new file mode 100644 index 0000000000000..7728fdaffb0dc --- /dev/null +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -0,0 +1,170 @@ +use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE}; +use rustc_middle::mir::*; +use rustc_middle::ty::layout; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::lint::builtin::FFI_UNWIND_CALLS; +use rustc_target::spec::abi::Abi; +use rustc_target::spec::PanicStrategy; + +fn abi_can_unwind(abi: Abi) -> bool { + use Abi::*; + match abi { + C { unwind } + | System { unwind } + | Cdecl { unwind } + | Stdcall { unwind } + | Fastcall { unwind } + | Vectorcall { unwind } + | Thiscall { unwind } + | Aapcs { unwind } + | Win64 { unwind } + | SysV64 { unwind } => unwind, + PtxKernel + | Msp430Interrupt + | X86Interrupt + | AmdGpuKernel + | EfiApi + | AvrInterrupt + | AvrNonBlockingInterrupt + | CCmseNonSecureCall + | Wasm + | RustIntrinsic + | PlatformIntrinsic + | Unadjusted => false, + Rust | RustCall | RustCold => true, + } +} + +// Check if the body of this def_id can possibly leak a foreign unwind into Rust code. +fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { + debug!("has_ffi_unwind_calls({local_def_id:?})"); + + // Only perform check on functions because constants cannot call FFI functions. + let def_id = local_def_id.to_def_id(); + let kind = tcx.def_kind(def_id); + if !kind.is_fn_like() { + return false; + } + + let body = &*tcx.mir_built(ty::WithOptConstParam::unknown(local_def_id)).borrow(); + + let body_ty = tcx.type_of(def_id); + let body_abi = match body_ty.kind() { + ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Generator(..) => Abi::Rust, + _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), + }; + let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi); + + // Foreign unwinds cannot leak past functions that themselves cannot unwind. + if !body_can_unwind { + return false; + } + + let mut tainted = false; + + for block in body.basic_blocks() { + if block.is_cleanup { + continue; + } + let Some(terminator) = &block.terminator else { continue }; + let TerminatorKind::Call { func, .. } = &terminator.kind else { continue }; + + let ty = func.ty(body, tcx); + let sig = ty.fn_sig(tcx); + + // Rust calls cannot themselves create foreign unwinds. + if let Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() { + continue; + }; + + let fn_def_id = match ty.kind() { + ty::FnPtr(_) => None, + &ty::FnDef(def_id, _) => { + // Rust calls cannot themselves create foreign unwinds. + if !tcx.is_foreign_item(def_id) { + continue; + } + Some(def_id) + } + _ => bug!("invalid callee of type {:?}", ty), + }; + + if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) && abi_can_unwind(sig.abi()) { + // We have detected a call that can possibly leak foreign unwind. + // + // Because the function body itself can unwind, we are not aborting this function call + // upon unwind, so this call can possibly leak foreign unwind into Rust code if the + // panic runtime linked is panic-abort. + + let lint_root = body.source_scopes[terminator.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + let span = terminator.source_info.span; + + tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| { + let msg = match fn_def_id { + Some(_) => "call to foreign function with FFI-unwind ABI", + None => "call to function pointer with FFI-unwind ABI", + }; + let mut db = lint.build(msg); + db.span_label(span, msg); + db.emit(); + }); + + tainted = true; + } + } + + tainted +} + +fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrategy> { + assert_eq!(cnum, LOCAL_CRATE); + + if tcx.is_panic_runtime(LOCAL_CRATE) { + return Some(tcx.sess.panic_strategy()); + } + + if tcx.sess.panic_strategy() == PanicStrategy::Abort { + return Some(PanicStrategy::Abort); + } + + for def_id in tcx.hir().body_owners() { + if tcx.has_ffi_unwind_calls(def_id) { + // Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls` + // MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception + // can enter Rust through these sites. + // + // On the other hand, crates compiled with `-C panic=abort` expects that all Rust + // functions cannot unwind (whether it's caused by Rust panic or foreign exception), + // and this expectation mismatch can cause unsoundness (#96926). + // + // To address this issue, we enforce that if FFI-unwind calls are used in a crate + // compiled with `panic=unwind`, then the final panic strategy must be `panic=unwind`. + // This will ensure that no crates will have wrong unwindability assumption. + // + // It should be noted that it is okay to link `panic=unwind` into a `panic=abort` + // program if it contains no FFI-unwind calls. In such case foreign exception can only + // enter Rust in a `panic=abort` crate, which will lead to an abort. There will also + // be no exceptions generated from Rust, so the assumption which `panic=abort` crates + // make, that no Rust function can unwind, indeed holds for crates compiled with + // `panic=unwind` as well. In such case this function returns `None`, indicating that + // the crate does not require a particular final panic strategy, and can be freely + // linked to crates with either strategy (we need such ability for libstd and its + // dependencies). + return Some(PanicStrategy::Unwind); + } + } + + // This crate can be linked with either runtime. + None +} + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { has_ffi_unwind_calls, required_panic_strategy, ..*providers }; +} diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 9078b8a1cb7cd..91ecf3879229d 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -67,7 +67,7 @@ use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_mir_dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, }; -use rustc_mir_dataflow::storage; +use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{self, Analysis}; use rustc_target::abi::VariantIdx; use rustc_target::spec::PanicStrategy; @@ -957,7 +957,7 @@ fn create_generator_drop_shim<'tcx>( tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }), source_info, ); - if tcx.sess.opts.debugging_opts.mir_emit_retag { + if tcx.sess.opts.unstable_opts.mir_emit_retag { // Alias tracking must know we changed the type body.basic_blocks_mut()[START_BLOCK].statements.insert( 0, @@ -1379,14 +1379,14 @@ impl<'tcx> MirPass<'tcx> for StateTransform { }, ); - let always_live_locals = storage::always_live_locals(&body); + let always_live_locals = always_storage_live_locals(&body); let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); - if tcx.sess.opts.debugging_opts.validate_mir { + if tcx.sess.opts.unstable_opts.validate_mir { let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { assigned_local: None, saved_locals: &liveness_info.saved_locals, diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 49403ba03a45d..dc5d5cee879f8 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,14 +1,15 @@ //! Inlining pass for MIR functions use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; +use rustc_const_eval::transform::validate::equal_up_to_regions; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_session::config::OptLevel; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; use rustc_target::spec::abi::Abi; @@ -39,11 +40,19 @@ struct CallSite<'tcx> { impl<'tcx> MirPass<'tcx> for Inline { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - if let Some(enabled) = sess.opts.debugging_opts.inline_mir { + if let Some(enabled) = sess.opts.unstable_opts.inline_mir { return enabled; } - sess.opts.mir_opt_level() >= 3 + match sess.mir_opt_level() { + 0 | 1 => false, + 2 => { + (sess.opts.optimize == OptLevel::Default + || sess.opts.optimize == OptLevel::Aggressive) + && sess.opts.incremental == None + } + _ => true, + } } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -76,13 +85,6 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { } let param_env = tcx.param_env_reveal_all_normalized(def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let param_env = rustc_trait_selection::traits::normalize_param_env_or_error( - tcx, - def_id.to_def_id(), - param_env, - ObligationCause::misc(body.span, hir_id), - ); let mut this = Inliner { tcx, @@ -166,6 +168,49 @@ impl<'tcx> Inliner<'tcx> { return Err("failed to normalize callee body"); }; + // Check call signature compatibility. + // Normally, this shouldn't be required, but trait normalization failure can create a + // validation ICE. + let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); + let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; + let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; + let output_type = callee_body.return_ty(); + if !equal_up_to_regions(self.tcx, self.param_env, output_type, destination_ty) { + trace!(?output_type, ?destination_ty); + return Err("failed to normalize return type"); + } + if callsite.fn_sig.abi() == Abi::RustCall { + let (arg_tuple, skipped_args) = match &args[..] { + [arg_tuple] => (arg_tuple, 0), + [_, arg_tuple] => (arg_tuple, 1), + _ => bug!("Expected `rust-call` to have 1 or 2 args"), + }; + + let arg_tuple_ty = arg_tuple.ty(&caller_body.local_decls, self.tcx); + let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else { + bug!("Closure arguments are not passed as a tuple"); + }; + + for (arg_ty, input) in + arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args)) + { + let input_type = callee_body.local_decls[input].ty; + if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + trace!(?arg_ty, ?input_type); + return Err("failed to normalize tuple argument type"); + } + } + } else { + for (arg, input) in args.iter().zip(callee_body.args_iter()) { + let input_type = callee_body.local_decls[input].ty; + let arg_ty = arg.ty(&caller_body.local_decls, self.tcx); + if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + trace!(?arg_ty, ?input_type); + return Err("failed to normalize argument type"); + } + } + } + let old_blocks = caller_body.basic_blocks().next_index(); self.inline_call(caller_body, &callsite, callee_body); let new_blocks = old_blocks..caller_body.basic_blocks().next_index(); @@ -263,6 +308,10 @@ impl<'tcx> Inliner<'tcx> { return None; } + if self.history.contains(&callee) { + return None; + } + let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs); return Some(CallSite { @@ -285,8 +334,14 @@ impl<'tcx> Inliner<'tcx> { callsite: &CallSite<'tcx>, callee_attrs: &CodegenFnAttrs, ) -> Result<(), &'static str> { - if let InlineAttr::Never = callee_attrs.inline { - return Err("never inline hint"); + match callee_attrs.inline { + InlineAttr::Never => return Err("never inline hint"), + InlineAttr::Always | InlineAttr::Hint => {} + InlineAttr::None => { + if self.tcx.sess.mir_opt_level() <= 2 { + return Err("at mir-opt-level=2, only #[inline] is inlined"); + } + } } // Only inline local functions if they would be eligible for cross-crate @@ -340,9 +395,9 @@ impl<'tcx> Inliner<'tcx> { let tcx = self.tcx; let mut threshold = if callee_attrs.requests_inline() { - self.tcx.sess.opts.debugging_opts.inline_mir_hint_threshold.unwrap_or(100) + self.tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) } else { - self.tcx.sess.opts.debugging_opts.inline_mir_threshold.unwrap_or(50) + self.tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50) }; // Give a bonus functions with a small number of blocks, @@ -407,22 +462,9 @@ impl<'tcx> Inliner<'tcx> { } TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { - if let ty::FnDef(def_id, substs) = + if let ty::FnDef(def_id, _) = *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() { - if let Ok(substs) = - self.tcx.try_normalize_erasing_regions(self.param_env, substs) - { - if let Ok(Some(instance)) = - Instance::resolve(self.tcx, self.param_env, def_id, substs) - { - if callsite.callee.def_id() == instance.def_id() { - return Err("self-recursion"); - } else if self.history.contains(&instance) { - return Err("already inlined"); - } - } - } // Don't give intrinsics the extra penalty for calls if tcx.is_intrinsic(def_id) { cost += INSTR_COST; @@ -482,14 +524,12 @@ impl<'tcx> Inliner<'tcx> { if let InlineAttr::Always = callee_attrs.inline { debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); Ok(()) + } else if cost <= threshold { + debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); + Ok(()) } else { - if cost <= threshold { - debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); - Ok(()) - } else { - debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); - Err("cost above threshold") - } + debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); + Err("cost above threshold") } } @@ -548,7 +588,7 @@ impl<'tcx> Inliner<'tcx> { ); expn_data.def_site = callee_body.span; let expn_data = - LocalExpnId::fresh(expn_data, self.tcx.create_stable_hashing_context()); + self.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx)); let mut integrator = Integrator { args: &args, new_locals: Local::new(caller_body.local_decls.len()).., diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index fd7de2bd1dcf8..a3a35f95071e9 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt}; use rustc_session::Limit; @@ -48,7 +48,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); continue; }; - let Some(callee) = ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() else { + let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, substs) else { trace!(?callee, "cannot resolve, skipping"); continue; }; diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index ea10ec5f25c15..2f3c65869ef3b 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -16,9 +16,8 @@ impl<'tcx> MirPass<'tcx> for InstCombine { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - let ctx = InstCombineContext { tcx, local_decls }; - for block in basic_blocks.iter_mut() { + let ctx = InstCombineContext { tcx, local_decls: &body.local_decls }; + for block in body.basic_blocks.as_mut() { for statement in block.statements.iter_mut() { match statement.kind { StatementKind::Assign(box (_place, ref mut rvalue)) => { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b7caa61ef07a7..40dc9fe9a05bb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,6 +1,6 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -28,7 +28,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::{Span, Symbol}; #[macro_use] @@ -59,6 +59,7 @@ pub mod dump_mir; mod early_otherwise_branch; mod elaborate_box_derefs; mod elaborate_drops; +mod ffi_unwind_calls; mod function_item_references; mod generator; mod inline; @@ -98,6 +99,7 @@ pub fn provide(providers: &mut Providers) { check_unsafety::provide(providers); check_packed_ref::provide(providers); coverage::query::provide(providers); + ffi_unwind_calls::provide(providers); shim::provide(providers); *providers = Providers { mir_keys, @@ -171,7 +173,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { intravisit::walk_struct_def(self, v) } } - tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }); + tcx.hir().visit_all_item_likes_in_crate(&mut GatherCtors { tcx, set: &mut set }); set } @@ -215,7 +217,7 @@ fn mir_const<'tcx>( } // Unsafety check uses the raw mir, so make sure it is run. - if !tcx.sess.opts.debugging_opts.thir_unsafeck { + if !tcx.sess.opts.unstable_opts.thir_unsafeck { if let Some(param_did) = def.const_param_did { tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did)); } else { @@ -223,6 +225,9 @@ fn mir_const<'tcx>( } } + // has_ffi_unwind_calls query uses the raw mir, so make sure it is run. + tcx.ensure().has_ffi_unwind_calls(def.did); + let mut body = tcx.mir_built(def).steal(); rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(())); @@ -415,6 +420,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc &remove_noop_landing_pads::RemoveNoopLandingPads, &cleanup_post_borrowck::CleanupNonCodegenStatements, &simplify::SimplifyCfg::new("early-opt"), + &deref_separator::Derefer, // These next passes must be executed together &add_call_guards::CriticalCallEdges, &elaborate_drops::ElaborateDrops, @@ -427,7 +433,6 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc &add_moves_for_packed_drops::AddMovesForPackedDrops, // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, // but before optimizations begin. - &deref_separator::Derefer, &elaborate_box_derefs::ElaborateBoxDerefs, &add_retag::AddRetag, &lower_intrinsics::LowerIntrinsics, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 989b94b68c101..b7ba616510c28 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -11,8 +11,8 @@ pub struct LowerIntrinsics; impl<'tcx> MirPass<'tcx> for LowerIntrinsics { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { + let local_decls = &body.local_decls; + for block in body.basic_blocks.as_mut() { let terminator = block.terminator.as_mut().unwrap(); if let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 07163cfe57510..47848cfa497f3 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -26,11 +26,11 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { return; }; - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - + // The one successor remains unchanged, so no need to invalidate + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); for block in basic_blocks { // lower `<[_]>::len` calls - lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id); + lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id); } } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 7cd7d26328a1a..a0ba69c89b048 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -48,7 +48,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { let def_id = body.source.def_id(); let param_env = tcx.param_env(def_id); - let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); + let bbs = body.basic_blocks.as_mut(); let mut should_cleanup = false; 'outer: for bb_idx in bbs.indices() { if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) { @@ -108,7 +108,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { // Introduce a temporary for the discriminant value. let source_info = bbs[bb_idx].terminator().source_info; - let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span)); + let discr_local = body.local_decls.push(LocalDecl::new(switch_ty, source_info.span)); // We already checked that first and second are different blocks, // and bb_idx has a different terminator from both of them. diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 0f45711baa3ac..c0217a105414b 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -32,7 +32,9 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { } pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + // We don't ever touch terminators, so no need to invalidate the CFG cache + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + let local_decls = &mut body.local_decls; // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]` let mut interesting_locals = BitSet::new_empty(local_decls.len()); diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index 444b4126e88fc..bb063915f55a9 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -133,7 +133,7 @@ fn find_local_assigned_to_return_place( return local; } - match body.predecessors()[block].as_slice() { + match body.basic_blocks.predecessors()[block].as_slice() { &[pred] => block = pred, _ => return None, } @@ -219,7 +219,7 @@ impl IsReturnPlaceRead { } impl<'tcx> Visitor<'tcx> for IsReturnPlaceRead { - fn visit_local(&mut self, &l: &Local, ctxt: PlaceContext, _: Location) { + fn visit_local(&mut self, l: Local, ctxt: PlaceContext, _: Location) { if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() { self.0 = true; } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 2380391d09a91..e27d4ab1688e0 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -76,8 +76,8 @@ pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn let start_phase = body.phase; let mut cnt = 0; - let validate = tcx.sess.opts.debugging_opts.validate_mir; - let overridden_passes = &tcx.sess.opts.debugging_opts.mir_enable_passes; + let validate = tcx.sess.opts.unstable_opts.validate_mir; + let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); if validate { diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs index c9b6e1459d323..dbe082e909371 100644 --- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs +++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs @@ -17,7 +17,7 @@ impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers { } trace!("Running RemoveStorageMarkers on {:?}", body.source); - for data in body.basic_blocks_mut() { + for data in body.basic_blocks.as_mut_preserves_cfg() { data.statements.retain(|statement| match statement.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index efa45883eab4b..c48aa9a90efbe 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -102,7 +102,7 @@ fn is_needs_drop_and_init<'tcx>( let field_needs_drop_and_init = |(f, f_ty, mpi)| { let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f)); let Some(mpi) = child else { - return f_ty.needs_drop(tcx, param_env); + return Ty::needs_drop(f_ty, tcx, param_env); }; is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi) diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 921a11a3a06d2..84ccf6e1f61d4 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -20,11 +20,10 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { let param_env = tcx.param_env_reveal_all_normalized(did); let mut should_simplify = false; - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks { + for block in body.basic_blocks.as_mut() { let terminator = block.terminator_mut(); if let TerminatorKind::Drop { place, target, .. } = terminator.kind { - let ty = place.ty(local_decls, tcx); + let ty = place.ty(&body.local_decls, tcx); if ty.ty.needs_drop(tcx, param_env) { continue; } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index aaee6f491cd33..40be4f146db98 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -18,8 +18,9 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts { return; } let param_env = tcx.param_env(body.source.def_id()); - let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); - for block in basic_blocks.iter_mut() { + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + 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 diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 33ea1c4ba2f59..925eb10a1f75f 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -61,7 +61,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch { /// Returns the amount of blocks that were duplicated pub fn separate_const_switch(body: &mut Body<'_>) -> usize { let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new(); - let predecessors = body.predecessors(); + let predecessors = body.basic_blocks.predecessors(); 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() { if let TerminatorKind::SwitchInt { discr: Operand::Copy(switch_place) | Operand::Move(switch_place), @@ -218,6 +218,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< // These rvalues move the place to track Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _) | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) + | Rvalue::CopyForDeref(place) | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place)) | Rvalue::Discriminant(place) => tracked_place = place, } @@ -279,6 +280,7 @@ fn find_determining_place<'tcx>( // that may be const in the predecessor Rvalue::Use(Operand::Move(new) | Operand::Copy(new)) | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new)) + | Rvalue::CopyForDeref(new) | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _) | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _) | Rvalue::Discriminant(new) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 3be1783ae3389..eaa61d8614d8c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -176,7 +176,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) if ty.is_some() { // The first argument (index 0), but add 1 for the return value. let dropee_ptr = Place::from(Local::new(1 + 0)); - if tcx.sess.opts.debugging_opts.mir_emit_retag { + if tcx.sess.opts.unstable_opts.mir_emit_retag { // Function arguments should be retagged, and we make this one raw. body.basic_blocks_mut()[START_BLOCK].statements.insert( 0, @@ -537,13 +537,12 @@ fn build_call_shim<'tcx>( }; let def_id = instance.def_id(); - let sig = tcx.fn_sig(def_id); - let mut sig = tcx.erase_late_bound_regions(sig); + let sig = tcx.bound_fn_sig(def_id); + let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig)); assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); - if let Some(sig_substs) = sig_substs { - sig = EarlyBinder(sig).subst(tcx, sig_substs); - } + let mut sig = + if let Some(sig_substs) = sig_substs { sig.subst(tcx, sig_substs) } else { sig.0 }; if let CallKind::Indirect(fnty) = call_kind { // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 8a78ea5c82bb1..980af98436281 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -509,12 +509,12 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { } } - fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) { + fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location) { if self.increment { - self.use_count[*local] += 1; + self.use_count[local] += 1; } else { - assert_ne!(self.use_count[*local], 0); - self.use_count[*local] -= 1; + assert_ne!(self.use_count[local], 0); + self.use_count[local] -= 1; } } } diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs index b3d45c7a22155..d52f1261b23a2 100644 --- a/compiler/rustc_mir_transform/src/simplify_try.rs +++ b/compiler/rustc_mir_transform/src/simplify_try.rs @@ -378,7 +378,7 @@ fn optimization_applies<'tcx>( impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // FIXME(77359): This optimization can result in unsoundness. - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + if !tcx.sess.opts.unstable_opts.unsound_mir_opts { return; } @@ -386,14 +386,17 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { trace!("running SimplifyArmIdentity on {:?}", source); let local_uses = LocalUseCounter::get_local_uses(body); - let (basic_blocks, local_decls, debug_info) = - body.basic_blocks_local_decls_mut_and_var_debug_info(); - for bb in basic_blocks { + for bb in body.basic_blocks.as_mut() { if let Some(opt_info) = - get_arm_identity_info(&bb.statements, local_decls.len(), debug_info) + get_arm_identity_info(&bb.statements, body.local_decls.len(), &body.var_debug_info) { trace!("got opt_info = {:#?}", opt_info); - if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) { + if !optimization_applies( + &opt_info, + &body.local_decls, + &local_uses, + &body.var_debug_info, + ) { debug!("optimization skipped for {:?}", source); continue; } @@ -431,7 +434,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { // Fix the debug info to point to the right local for dbg_index in opt_info.dbg_info_to_adjust { - let dbg_info = &mut debug_info[dbg_index]; + let dbg_info = &mut body.var_debug_info[dbg_index]; assert!( matches!(dbg_info.value, VarDebugInfoContents::Place(_)), "value was not a Place" @@ -462,14 +465,14 @@ impl LocalUseCounter { } impl Visitor<'_> for LocalUseCounter { - fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) { + fn visit_local(&mut self, local: Local, context: PlaceContext, _location: Location) { if context.is_storage_marker() || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { return; } - self.local_uses[*local] += 1; + self.local_uses[local] += 1; } } @@ -548,7 +551,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // This optimization is disabled by default for now due to // soundness concerns; see issue #89485 and PR #89489. - if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + if !tcx.sess.opts.unstable_opts.unsound_mir_opts { return; } diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index e4ac47f4982cb..41ba4d4b64a34 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" doctest = false [dependencies] -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2af22e129a5f7..d9fa4d65b3a9a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -194,7 +194,9 @@ use rustc_middle::mir::{self, Local, Location}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry}; +use rustc_middle::ty::{ + self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitable, VtblEntry, +}; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; use rustc_session::config::EntryFnType; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; @@ -730,7 +732,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { def_id, substs, ty::ClosureKind::FnOnce, - ); + ) + .expect("failed to normalize and resolve closure during codegen"); if should_codegen_locally(self.tcx, &instance) { self.output.push(create_fn_mono_item(self.tcx, instance, span)); } @@ -928,7 +931,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_local( &mut self, - _place_local: &Local, + _place_local: Local, _context: mir::visit::PlaceContext, _location: Location, ) { @@ -1138,8 +1141,7 @@ fn create_fn_mono_item<'tcx>( debug!("create_fn_mono_item(instance={})", instance); let def_id = instance.def_id(); - if tcx.sess.opts.debugging_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) - { + if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) { crate::util::dump_closure_profile(tcx, instance); } diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 320765e7af34a..d18b1c26c174f 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -9,7 +9,7 @@ use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::ty::print::characteristic_def_id_of_type; -use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, visit::TypeVisitable, DefIdTree, InstanceDef, TyCtxt}; use rustc_span::symbol::Symbol; use super::PartitioningCx; @@ -303,7 +303,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( // When polymorphization is enabled, methods which do not depend on their generic // parameters, but the self-type of their impl block do will fail to normalize. - if !tcx.sess.opts.debugging_opts.polymorphize || !instance.needs_subst() { + if !tcx.sess.opts.unstable_opts.polymorphize || !instance.needs_subst() { // This is a method within an impl, find out what the self-type is: let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, diff --git a/compiler/rustc_monomorphize/src/partitioning/merging.rs b/compiler/rustc_monomorphize/src/partitioning/merging.rs index 09cadc907b18a..02bb8dea0c01e 100644 --- a/compiler/rustc_monomorphize/src/partitioning/merging.rs +++ b/compiler/rustc_monomorphize/src/partitioning/merging.rs @@ -83,7 +83,7 @@ pub fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names { + if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { cgu.set_name(Symbol::intern(&new_cgu_name)); } else { // If we don't require CGU names to be human-readable, we diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index c1992137575bc..36243803f994e 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -141,7 +141,7 @@ trait Partitioner<'tcx> { } fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> { - let strategy = match &tcx.sess.opts.debugging_opts.cgu_partitioning_strategy { + let strategy = match &tcx.sess.opts.unstable_opts.cgu_partitioning_strategy { None => "default", Some(s) => &s[..], }; @@ -345,7 +345,7 @@ fn collect_and_partition_mono_items<'tcx>( tcx: TyCtxt<'tcx>, (): (), ) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { - let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { + let collection_mode = match tcx.sess.opts.unstable_opts.print_mono_items { Some(ref s) => { let mode_string = s.to_lowercase(); let mode_string = mode_string.trim(); @@ -413,7 +413,7 @@ fn collect_and_partition_mono_items<'tcx>( }) .collect(); - if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { + if tcx.sess.opts.unstable_opts.print_mono_items.is_some() { let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); for cgu in codegen_units { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index f29143b448049..394843e510d21 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -13,9 +13,9 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{ self, - fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor}, query::Providers, subst::SubstsRef, + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, Const, Ty, TyCtxt, }; use rustc_span::symbol::sym; @@ -36,7 +36,7 @@ fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, ) -> FiniteBitSet<u32> { - if !tcx.sess.opts.debugging_opts.polymorphize { + if !tcx.sess.opts.unstable_opts.polymorphize { // If polymorphization disabled, then all parameters are used. return FiniteBitSet::new_empty(); } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f3bdd63ee6dd4..d56e3773dc7a0 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,9 +3,10 @@ #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(never_type)] +#![feature(rustc_attrs)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ba325d704228d..63055c56c5c6d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -244,7 +244,7 @@ impl MultiSugg { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-maybe-report-ambiguous-plus")] +#[error(parser::maybe_report_ambiguous_plus)] struct AmbiguousPlus { pub sum_ty: String, #[primary_span] @@ -253,7 +253,7 @@ struct AmbiguousPlus { } #[derive(SessionDiagnostic)] -#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")] +#[error(parser::maybe_recover_from_bad_type_plus, code = "E0178")] struct BadTypePlus { pub ty: String, #[primary_span] @@ -265,7 +265,7 @@ struct BadTypePlus { #[derive(SessionSubdiagnostic)] pub enum BadTypePlusSub { #[suggestion( - slug = "parser-add-paren", + parser::add_paren, code = "{sum_with_parens}", applicability = "machine-applicable" )] @@ -274,12 +274,12 @@ pub enum BadTypePlusSub { #[primary_span] span: Span, }, - #[label(slug = "parser-forgot-paren")] + #[label(parser::forgot_paren)] ForgotParen { #[primary_span] span: Span, }, - #[label(slug = "parser-expect-path")] + #[label(parser::expect_path)] ExpectPath { #[primary_span] span: Span, @@ -287,7 +287,7 @@ pub enum BadTypePlusSub { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")] +#[error(parser::maybe_recover_from_bad_qpath_stage_2)] struct BadQPathStage2 { #[primary_span] #[suggestion(applicability = "maybe-incorrect")] @@ -296,7 +296,7 @@ struct BadQPathStage2 { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-incorrect-semicolon")] +#[error(parser::incorrect_semicolon)] struct IncorrectSemicolon<'a> { #[primary_span] #[suggestion_short(applicability = "machine-applicable")] @@ -307,26 +307,26 @@ struct IncorrectSemicolon<'a> { } #[derive(SessionDiagnostic)] -#[error(slug = "parser-incorrect-use-of-await")] +#[error(parser::incorrect_use_of_await)] struct IncorrectUseOfAwait { #[primary_span] - #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")] + #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")] span: Span, } #[derive(SessionDiagnostic)] -#[error(slug = "parser-incorrect-use-of-await")] +#[error(parser::incorrect_use_of_await)] struct IncorrectAwait { #[primary_span] span: Span, - #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")] + #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")] sugg_span: (Span, Applicability), expr: String, question_mark: &'static str, } #[derive(SessionDiagnostic)] -#[error(slug = "parser-in-in-typo")] +#[error(parser::in_in_typo)] struct InInTypo { #[primary_span] span: Span, @@ -357,6 +357,7 @@ impl<'a> DerefMut for SnapshotParser<'a> { } impl<'a> Parser<'a> { + #[rustc_lint_diagnostics] pub(super) fn span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -365,6 +366,7 @@ impl<'a> Parser<'a> { err.span_err(sp, self.diagnostic()) } + #[rustc_lint_diagnostics] pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 81bab0e3513c9..8e1b279d9b6c2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -7,6 +7,7 @@ use super::{ }; use crate::maybe_recover_from_interpolated_ty_qpath; +use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::Spacing; @@ -14,10 +15,10 @@ use rustc_ast::util::classify; use rustc_ast::util::literal::LitError; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::visit::Visitor; -use rustc_ast::StmtKind; use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID}; use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; +use rustc_ast::{ClosureBinder, StmtKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult}; @@ -26,7 +27,6 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; -use std::mem; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of @@ -1343,11 +1343,7 @@ impl<'a> Parser<'a> { self.parse_if_expr(attrs) } else if self.check_keyword(kw::For) { if self.choose_generics_over_qpath(1) { - // NOTE(Centril, eddyb): DO NOT REMOVE! Beyond providing parser recovery, - // this is an insurance policy in case we allow qpaths in (tuple-)struct patterns. - // When `for <Foo as Bar>::Proj in $expr $block` is wanted, - // you can disambiguate in favor of a pattern with `(...)`. - self.recover_quantified_closure_expr(attrs) + self.parse_closure_expr(attrs) } else { assert!(self.eat_keyword(kw::For)); self.parse_for_expr(None, self.prev_token.span, attrs) @@ -1393,7 +1389,9 @@ impl<'a> Parser<'a> { self.parse_yield_expr(attrs) } else if self.is_do_yeet() { self.parse_yeet_expr(attrs) - } else if self.eat_keyword(kw::Let) { + } else if self.check_keyword(kw::Let) { + self.manage_let_chains_context(); + self.bump(); self.parse_let_expr(attrs) } else if self.eat_keyword(kw::Underscore) { Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs)) @@ -2094,29 +2092,21 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())) } - /// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`. - fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { + /// Parses a closure expression (e.g., `move |args| expr`). + fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { let lo = self.token.span; - let _ = self.parse_late_bound_lifetime_defs()?; - let span_for = lo.to(self.prev_token.span); - let closure = self.parse_closure_expr(attrs)?; - self.struct_span_err(span_for, "cannot introduce explicit parameters for a closure") - .span_label(closure.span, "the parameters are attached to this closure") - .span_suggestion( - span_for, - "remove the parameters", - "", - Applicability::MachineApplicable, - ) - .emit(); + let binder = if self.check_keyword(kw::For) { + let lo = self.token.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let span = lo.to(self.prev_token.span); - Ok(self.mk_expr_err(lo.to(closure.span))) - } + self.sess.gated_spans.gate(sym::closure_lifetime_binder, span); - /// Parses a closure expression (e.g., `move |args| expr`). - fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { - let lo = self.token.span; + ClosureBinder::For { span, generic_params: P::from_vec(lifetime_defs) } + } else { + ClosureBinder::NotPresent + }; let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; @@ -2160,7 +2150,15 @@ impl<'a> Parser<'a> { let closure = self.mk_expr( lo.to(body.span), - ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)), + ExprKind::Closure( + binder, + capture_clause, + asyncness, + movability, + decl, + body, + lo.to(decl_hi), + ), attrs, ); @@ -2343,14 +2341,30 @@ impl<'a> Parser<'a> { /// Parses the condition of a `if` or `while` expression. fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> { - let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + self.with_let_management(true, |local_self| { + local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) + }) + } - if let ExprKind::Let(..) = cond.kind { - // Remove the last feature gating of a `let` expression since it's stable. - self.sess.gated_spans.ungate_last(sym::let_chains, cond.span); + // Checks if `let` is in an invalid position like `let x = let y = 1;` or + // if the current `let` is in a let_chains context but nested in another + // expression like `if let Some(_) = _opt && [1, 2, 3][let _ = ()] = 1`. + // + // This method expects that the current token is `let`. + fn manage_let_chains_context(&mut self) { + debug_assert!(matches!(self.token.kind, TokenKind::Ident(kw::Let, _))); + let is_in_a_let_chains_context_but_nested_in_other_expr = self.let_expr_allowed + && !matches!( + self.prev_token.kind, + TokenKind::AndAnd + | TokenKind::CloseDelim(Delimiter::Brace) + | TokenKind::Ident(kw::If, _) + | TokenKind::Ident(kw::While, _) + ); + if !self.let_expr_allowed || is_in_a_let_chains_context_but_nested_in_other_expr { + self.struct_span_err(self.token.span, "expected expression, found `let` statement") + .emit(); } - - Ok(cond) } /// Parses a `let $pat = $expr` pseudo-expression. @@ -2368,7 +2382,6 @@ impl<'a> Parser<'a> { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) })?; let span = lo.to(expr.span); - self.sess.gated_spans.gate(sym::let_chains, span); Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span), attrs)) } @@ -2672,15 +2685,13 @@ impl<'a> Parser<'a> { } pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { - fn check_let_expr(expr: &Expr) -> (bool, bool) { + // Used to check the `let_chains` and `if_let_guard` features mostly by scaning + // `&&` tokens. + fn check_let_expr(expr: &Expr) -> bool { match expr.kind { - ExprKind::Binary(_, ref lhs, ref rhs) => { - let lhs_rslt = check_let_expr(lhs); - let rhs_rslt = check_let_expr(rhs); - (lhs_rslt.0 || rhs_rslt.0, false) - } - ExprKind::Let(..) => (true, true), - _ => (false, true), + ExprKind::Binary(_, ref lhs, ref rhs) => check_let_expr(lhs) || check_let_expr(rhs), + ExprKind::Let(..) => true, + _ => false, } } let attrs = self.parse_outer_attributes()?; @@ -2694,13 +2705,9 @@ impl<'a> Parser<'a> { )?; let guard = if this.eat_keyword(kw::If) { let if_span = this.prev_token.span; - let cond = this.parse_expr()?; - let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond); + let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?; + let has_let_expr = check_let_expr(&cond); if has_let_expr { - if does_not_have_bin_op { - // Remove the last feature gating of a `let` expression since it's stable. - this.sess.gated_spans.ungate_last(sym::let_chains, cond.span); - } let span = if_span.to(cond.span); this.sess.gated_spans.gate(sym::if_let_guard, span); } @@ -3001,6 +3008,11 @@ impl<'a> Parser<'a> { } }; + let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand); + // A shorthand field can be turned into a full field with `:`. + // We should point this out. + self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon)); + match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { Ok(_) => { if let Some(f) = parsed_field.or(recovery_field) { @@ -3021,6 +3033,19 @@ impl<'a> Parser<'a> { ",", Applicability::MachineApplicable, ); + } else if is_shorthand + && (AssocOp::from_token(&self.token).is_some() + || matches!(&self.token.kind, token::OpenDelim(_)) + || self.token.kind == token::Dot) + { + // Looks like they tried to write a shorthand, complex expression. + let ident = parsed_field.expect("is_shorthand implies Some").ident; + e.span_suggestion( + ident.span.shrink_to_lo(), + "try naming a field", + &format!("{ident}: "), + Applicability::HasPlaceholders, + ); } } if !recover { @@ -3256,4 +3281,17 @@ impl<'a> Parser<'a> { Ok((res, trailing)) }) } + + // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then + // sets the internal `let_expr_allowed` back to its original value. + fn with_let_management<T>( + &mut self, + let_expr_allowed: bool, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed); + let rslt = f(self); + self.let_expr_allowed = last_let_expr_allowed; + rslt + } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bf685aa8cadc3..87bc0d9762ea5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -271,8 +271,7 @@ impl<'a> Parser<'a> { // MACRO_RULES ITEM self.parse_item_macro_rules(vis, has_bang)? } else if self.isnt_macro_invocation() - && (self.token.is_ident_named(Symbol::intern("import")) - || self.token.is_ident_named(Symbol::intern("using"))) + && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using)) { return self.recover_import_as_use(); } else if self.isnt_macro_invocation() && vis.kind.is_pub() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 6d6667717f0a3..67e6402c0ae78 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -147,12 +147,15 @@ pub struct Parser<'a> { /// This allows us to recover when the user forget to add braces around /// multiple statements in the closure body. pub current_closure: Option<ClosureSpans>, + /// Used to track where `let`s are allowed. For example, `if true && let 1 = 1` is valid + /// but `[1, 2, 3][let _ = ()]` is not. + let_expr_allowed: bool, } // This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure // it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Parser<'_>, 328); +rustc_data_structures::static_assert_size!(Parser<'_>, 336); /// Stores span information about a closure. #[derive(Clone)] @@ -455,6 +458,7 @@ impl<'a> Parser<'a> { inner_attr_ranges: Default::default(), }, current_closure: None, + let_expr_allowed: false, }; // Make parser point to the first token. @@ -887,22 +891,19 @@ impl<'a> Parser<'a> { let mut first_note = MultiSpan::from(vec![initial_semicolon]); first_note.push_span_label( initial_semicolon, - "this `;` turns the preceding closure into a statement".to_string(), + "this `;` turns the preceding closure into a statement", ); first_note.push_span_label( closure_spans.body, - "this expression is a statement because of the trailing semicolon".to_string(), + "this expression is a statement because of the trailing semicolon", ); expect_err.span_note(first_note, "statement found outside of a block"); let mut second_note = MultiSpan::from(vec![closure_spans.whole_closure]); - second_note.push_span_label( - closure_spans.whole_closure, - "this is the parsed closure...".to_string(), - ); + second_note.push_span_label(closure_spans.whole_closure, "this is the parsed closure..."); second_note.push_span_label( following_token_span, - "...but likely you meant the closure to end here".to_string(), + "...but likely you meant the closure to end here", ); expect_err.span_note(second_note, "the closure body may be incorrectly delimited"); @@ -1352,7 +1353,16 @@ impl<'a> Parser<'a> { /// Parses `extern string_literal?`. fn parse_extern(&mut self) -> Extern { - if self.eat_keyword(kw::Extern) { Extern::from_abi(self.parse_abi()) } else { Extern::None } + if self.eat_keyword(kw::Extern) { + let mut extern_span = self.prev_token.span; + let abi = self.parse_abi(); + if let Some(abi) = abi { + extern_span = extern_span.to(abi.span); + } + Extern::from_abi(abi, extern_span) + } else { + Extern::None + } } /// Parses a string literal as an ABI spec. diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 676812db59ae5..faa9c493d8875 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } +rustc_macros = { path = "../rustc_macros" } rustc_ast = { path = "../rustc_ast" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 536d45b2399b1..d96e7d3efe83d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,9 +4,10 @@ //! conflicts between multiple such attributes attached to the same //! item. +use crate::errors; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; +use rustc_errors::{fluent, pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -139,6 +140,7 @@ impl CheckAttrVisitor<'_> { | sym::rustc_const_stable | sym::unstable | sym::stable + | sym::rustc_allowed_through_unstable_modules | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target), _ => true, }; @@ -174,16 +176,20 @@ impl CheckAttrVisitor<'_> { if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - let msg = match attr.style { - ast::AttrStyle::Outer => { - "crate-level attribute should be an inner attribute: add an exclamation \ - mark: `#![foo]`" - } - ast::AttrStyle::Inner => "crate-level attribute should be in the root module", - }; - lint.build(msg).emit(); - }); + match attr.style { + ast::AttrStyle::Outer => self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::InnerCrateLevelAttr, + ), + } } } @@ -208,37 +214,21 @@ impl CheckAttrVisitor<'_> { } fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!( - "`#[{sym}]` is ignored on struct fields, match arms and macro defs", - )) - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .note( - "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \ - for more information", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredAttrWithMacro { sym }, + ); } fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!("`#[{sym}]` is ignored on struct fields and match arms")) - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .note( - "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \ - for more information", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredAttr { sym }, + ); } /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. @@ -248,9 +238,12 @@ impl CheckAttrVisitor<'_> { | Target::Closure | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[inline]` is ignored on function prototypes").emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredInlineAttrFnProto, + ); true } // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with @@ -258,19 +251,12 @@ impl CheckAttrVisitor<'_> { // accidentally, to to be compatible with crates depending on them, we can't throw an // error here. Target::AssocConst => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[inline]` is ignored on constants") - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .note( - "see issue #65833 <https://github.com/rust-lang/rust/issues/65833> \ - for more information", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredInlineAttrConstants, + ); true } // FIXME(#80564): Same for fields, arms, and macro defs @@ -279,14 +265,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - struct_span_err!( - self.tcx.sess, - attr.span, - E0518, - "attribute should be applied to function or closure", - ) - .span_label(span, "not a function or closure") - .emit(); + self.tcx.sess.emit_err(errors::InlineNotFnOrClosure { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -308,36 +290,40 @@ impl CheckAttrVisitor<'_> { // function prototypes can't be covered Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[no_coverage]` is ignored on function prototypes").emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredNoCoverageFnProto, + ); true } Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredNoCoveragePropagate, + ); true } Target::Expression | Target::Statement | Target::Arm => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("`#[no_coverage]` may only be applied to function definitions") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::IgnoredNoCoverageFnDefn, + ); true } _ => { - struct_span_err!( - self.tcx.sess, - attr.span, - E0788, - "`#[no_coverage]` must be applied to coverable code", - ) - .span_label(span, "not coverable code") - .emit(); + self.tcx.sess.emit_err(errors::IgnoredNoCoverageNotCoverable { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -388,14 +374,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "attribute should be applied to a function definition", - ) - .span_label(span, "not a function definition") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -407,14 +389,10 @@ impl CheckAttrVisitor<'_> { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "attribute should be applied to a function definition", - ) - .span_label(span, "not a function definition") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -431,13 +409,7 @@ impl CheckAttrVisitor<'_> { ) -> bool { match target { _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { - struct_span_err!( - self.tcx.sess, - attr_span, - E0736, - "cannot use `#[track_caller]` with `#[naked]`", - ) - .emit(); + self.tcx.sess.emit_err(errors::NakedTrackedCaller { attr_span }); false } Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, @@ -452,14 +424,9 @@ impl CheckAttrVisitor<'_> { true } _ => { - struct_span_err!( - self.tcx.sess, - attr_span, - E0739, - "attribute should be applied to function" - ) - .span_label(span, "not a function") - .emit(); + self.tcx + .sess + .emit_err(errors::TrackedCallerWrongLocation { attr_span, defn_span: span }); false } } @@ -484,14 +451,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - struct_span_err!( - self.tcx.sess, - attr.span, - E0701, - "attribute can only be applied to a struct or enum" - ) - .span_label(span, "not a struct or enum") - .emit(); + self.tcx.sess.emit_err(errors::NonExhaustiveWrongLocation { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -510,11 +473,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute can only be applied to a trait") - .span_label(span, "not a trait") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -530,11 +492,10 @@ impl CheckAttrVisitor<'_> { match target { Target::Trait => true, _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute can only be applied to a trait") - .span_label(span, "not a trait") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -554,16 +515,12 @@ impl CheckAttrVisitor<'_> { // FIXME: #[target_feature] was previously erroneously allowed on statements and some // crates used this, so only emit a warning. Target::Statement => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("attribute should be applied to a function") - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .span_label(span, "not a function") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::TargetFeatureOnStatement, + ); true } // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -575,11 +532,10 @@ impl CheckAttrVisitor<'_> { true } _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(span, "not a function") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn { + attr_span: attr.span, + defn_span: span, + }); false } } @@ -590,24 +546,17 @@ impl CheckAttrVisitor<'_> { match target { Target::ForeignStatic | Target::Static => true, _ => { - self.tcx - .sess - .struct_span_err(attr.span, "attribute should be applied to a static") - .span_label(span, "not a static") - .emit(); + self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToStatic { + attr_span: attr.span, + defn_span: span, + }); false } } } fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name), - ) - .emit(); + self.tcx.sess.emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); } fn check_doc_alias_value( @@ -620,22 +569,12 @@ impl CheckAttrVisitor<'_> { aliases: &mut FxHashMap<String, Span>, ) -> bool { let tcx = self.tcx; - let err_fn = move |span: Span, msg: &str| { - tcx.sess.span_err( - span, - &format!( - "`#[doc(alias{})]` {}", - if is_list { "(\"...\")" } else { " = \"...\"" }, - msg, - ), - ); - false - }; + let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span()); + let attr_str = + &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" }); if doc_alias == kw::Empty { - return err_fn( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - "attribute cannot have empty value", - ); + tcx.sess.emit_err(errors::DocAliasEmpty { span, attr_str }); + return false; } let doc_alias_str = doc_alias.as_str(); @@ -643,23 +582,16 @@ impl CheckAttrVisitor<'_> { .chars() .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) { - self.tcx.sess.span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - &format!( - "{:?} character isn't allowed in `#[doc(alias{})]`", - c, - if is_list { "(\"...\")" } else { " = \"...\"" }, - ), - ); + tcx.sess.emit_err(errors::DocAliasBadChar { span, attr_str, char_: c }); return false; } if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') { - return err_fn( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - "cannot start or end with ' '", - ); + tcx.sess.emit_err(errors::DocAliasStartEnd { span, attr_str }); + return false; } - if let Some(err) = match target { + + let span = meta.span(); + if let Some(location) = match target { Target::Impl => Some("implementation block"), Target::ForeignMod => Some("extern block"), Target::AssocTy => { @@ -685,19 +617,21 @@ impl CheckAttrVisitor<'_> { Target::Param => return false, _ => None, } { - return err_fn(meta.span(), &format!("isn't allowed on {}", err)); + tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location }); + return false; } let item_name = self.tcx.hir().name(hir_id); if item_name == doc_alias { - return err_fn(meta.span(), "is the same as the item's name"); + tcx.sess.emit_err(errors::DocAliasNotAnAlias { span, attr_str }); + return false; } - let span = meta.span(); if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { - lint.build("doc alias is duplicated") - .span_label(*entry.entry.get(), "first defined here") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + span, + errors::DocAliasDuplicated { first_defn: *entry.entry.get() }, + ); } true } @@ -722,22 +656,12 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .struct_span_err( - v.span(), - "`#[doc(alias(\"a\"))]` expects string literals", - ) - .emit(); + .emit_err(errors::DocAliasNotStringLiteral { span: v.span() }); errors += 1; } }, None => { - self.tcx - .sess - .struct_span_err( - v.span(), - "`#[doc(alias(\"a\"))]` expects string literals", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocAliasNotStringLiteral { span: v.span() }); errors += 1; } } @@ -746,14 +670,7 @@ impl CheckAttrVisitor<'_> { } else if let Some(doc_alias) = meta.value_str() { self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases) } else { - self.tcx - .sess - .struct_span_err( - meta.span(), - "doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \ - strings `#[doc(alias(\"a\", \"b\"))]`", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocAliasMalformed { span: meta.span() }); false } } @@ -770,35 +687,20 @@ impl CheckAttrVisitor<'_> { }) { Some(ItemKind::Mod(ref module)) => { if !module.item_ids.is_empty() { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(keyword = \"...\")]` can only be used on empty modules", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordEmptyMod { span: meta.span() }); return false; } } _ => { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(keyword = \"...\")]` can only be used on modules", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordNotMod { span: meta.span() }); return false; } } if !rustc_lexer::is_ident(doc_keyword.as_str()) { - self.tcx - .sess - .struct_span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - &format!("`{doc_keyword}` is not a valid identifier"), - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordInvalidIdent { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + doc_keyword, + }); return false; } true @@ -811,24 +713,12 @@ impl CheckAttrVisitor<'_> { }) { Some(ItemKind::Impl(ref i)) => { if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocTupleVariadicNotFirst { span: meta.span() }); return false; } } _ => { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#[doc(keyword = \"...\")]` can only be used on impl blocks", - ) - .emit(); + self.tcx.sess.emit_err(errors::DocKeywordOnlyImpl { span: meta.span() }); return false; } } @@ -857,16 +747,9 @@ impl CheckAttrVisitor<'_> { if let Some((prev_inline, prev_span)) = *specified_inline { if do_inline != prev_inline { let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]); - spans.push_span_label(prev_span, String::from("this attribute...")); - spans.push_span_label( - meta.span(), - String::from("...conflicts with this attribute"), - ); - self.tcx - .sess - .struct_span_err(spans, "conflicting doc inlining attributes") - .help("remove one of the conflicting attributes") - .emit(); + spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first); + spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second); + self.tcx.sess.emit_err(errors::DocKeywordConflict { spans }); return false; } true @@ -875,23 +758,14 @@ impl CheckAttrVisitor<'_> { true } } else { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), - |lint| { - let mut err = lint.build( - "this attribute can only be applied to a `use` item", - ); - err.span_label(meta.span(), "only applicable on `use` items"); - if attr.style == AttrStyle::Outer { - err.span_label( - self.tcx.hir().span(hir_id), - "not a `use` item", - ); - } - err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information") - .emit(); + errors::DocInlineOnlyUse { + attr_span: meta.span(), + item_span: (attr.style == AttrStyle::Outer) + .then(|| self.tcx.hir().span(hir_id)), }, ); false @@ -906,15 +780,7 @@ impl CheckAttrVisitor<'_> { attr_name: &str, ) -> bool { if CRATE_HIR_ID == hir_id { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!( - "`#![doc({attr_name} = \"...\")]` isn't allowed as a crate-level attribute", - ), - ) - .emit(); + self.tcx.sess.emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name }); return false; } true @@ -928,36 +794,25 @@ impl CheckAttrVisitor<'_> { hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { - self.tcx.struct_span_lint_hir( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - |lint| { - let mut err = lint.build( - "this attribute can only be applied at the crate level", - ); - if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID { - if let Ok(mut src) = - self.tcx.sess.source_map().span_to_snippet(attr.span) - { - src.insert(1, '!'); - err.span_suggestion_verbose( - attr.span, - "to apply to the crate, use an inner attribute", - src, - Applicability::MaybeIncorrect, - ); - } else { - err.span_help( - attr.span, - "to apply to the crate, use an inner attribute", - ); - } + self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| { + let mut err = lint.build(fluent::passes::attr_crate_level); + if attr.style == AttrStyle::Outer + && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID + { + if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) { + src.insert(1, '!'); + err.span_suggestion_verbose( + attr.span, + fluent::passes::suggestion, + src, + Applicability::MaybeIncorrect, + ); + } else { + err.span_help(attr.span, fluent::passes::help); } - err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information") - .emit(); - }, - ); + } + err.note(fluent::passes::note).emit(); + }); return false; } true @@ -972,18 +827,14 @@ impl CheckAttrVisitor<'_> { match i_meta.name_or_empty() { sym::attr | sym::no_crate_inject => {} _ => { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span(), - |lint| { - lint.build(&format!( - "unknown `doc(test)` attribute `{}`", - rustc_ast_pretty::pprust::path_to_string( - &i_meta.meta_item().unwrap().path - ), - )) - .emit(); + errors::DocTestUnknown { + path: rustc_ast_pretty::pprust::path_to_string( + &i_meta.meta_item().unwrap().path, + ), }, ); is_valid = false; @@ -991,9 +842,12 @@ impl CheckAttrVisitor<'_> { } } } else { - self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| { - lint.build("`#[doc(test(...)]` takes a list of attributes").emit(); - }); + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocTestTakesList, + ); is_valid = false; } is_valid @@ -1095,79 +949,66 @@ impl CheckAttrVisitor<'_> { sym::primitive => { if !self.tcx.features().rustdoc_internals { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, - |lint| { - let mut diag = lint.build( - "`doc(primitive)` should never have been stable", - ); - diag.emit(); - }, + errors::DocPrimitive, ); } } _ => { - self.tcx.struct_span_lint_hir( - INVALID_DOC_ATTRIBUTES, - hir_id, - i_meta.span, - |lint| { - let mut diag = lint.build(&format!( - "unknown `doc` attribute `{}`", - rustc_ast_pretty::pprust::path_to_string(&i_meta.path), - )); - if i_meta.has_name(sym::spotlight) { - diag.note( - "`doc(spotlight)` was renamed to `doc(notable_trait)`", - ); - diag.span_suggestion_short( - i_meta.span, - "use `notable_trait` instead", - "notable_trait", - Applicability::MachineApplicable, - ); - diag.note("`doc(spotlight)` is now a no-op"); + let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path); + if i_meta.has_name(sym::spotlight) { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownSpotlight { + path, + span: i_meta.span } - if i_meta.has_name(sym::include) { - if let Some(value) = i_meta.value_str() { - // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect - let applicability = if list.len() == 1 { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - let inner = if attr.style == AttrStyle::Inner { - "!" - } else { - "" - }; - diag.span_suggestion( - attr.meta().unwrap().span, - "use `doc = include_str!` instead", - format!( - "#{inner}[doc = include_str!(\"{value}\")]", - ), - applicability, - ); - } + ); + } else if i_meta.has_name(sym::include) && + let Some(value) = i_meta.value_str() { + let applicability = if list.len() == 1 { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + // If there are multiple attributes, the suggestion would suggest + // deleting all of them, which is incorrect. + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownInclude { + path, + value: value.to_string(), + inner: (attr.style == AttrStyle::Inner) + .then_some("!") + .unwrap_or(""), + sugg: (attr.meta().unwrap().span, applicability), } - diag.emit(); - }, - ); + ); + } else { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + i_meta.span, + errors::DocTestUnknownAny { path } + ); + } is_valid = false; } } } else { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), - |lint| { - lint.build(&"invalid `doc` attribute").emit(); - }, + errors::DocInvalid, ); is_valid = false; } @@ -1182,14 +1023,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Struct | Target::Enum | Target::TyAlias => true, _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "`pass_by_value` attribute should be applied to a struct, enum or type alias.", - ) - .span_label(span, "is not a struct, enum or type alias") - .emit(); + self.tcx.sess.emit_err(errors::PassByValue { attr_span: attr.span, span }); false } } @@ -1199,14 +1033,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Method(MethodKind::Inherent) => true, _ => { - self.tcx - .sess - .struct_span_err( - attr.span, - "`rustc_allow_incoherent_impl` attribute should be applied to impl items.", - ) - .span_label(span, "the only currently supported targets are inherent methods") - .emit(); + self.tcx.sess.emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span }); false } } @@ -1225,12 +1052,7 @@ impl CheckAttrVisitor<'_> { _ => { self.tcx .sess - .struct_span_err( - attr.span, - "`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.", - ) - .span_label(span, "only adts, extern types and traits are supported") - .emit(); + .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span }); false } } @@ -1240,19 +1062,12 @@ impl CheckAttrVisitor<'_> { fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { let node = self.tcx.hir().get(hir_id); if let Some(kind) = node.fn_kind() && let rustc_hir::IsAsync::Async = kind.asyncness() { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build( - "`must_use` attribute on `async` functions \ - applies to the anonymous `Future` returned by the \ - function, not the value within", - ) - .span_label( - span, - "this attribute does nothing, the `Future`s \ - returned by async functions are already `must_use`", - ) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MustUseAsync { span } + ); } if !matches!( @@ -1280,12 +1095,12 @@ impl CheckAttrVisitor<'_> { _ => "a", }; - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build(&format!( - "`#[must_use]` has no effect when applied to {article} {target}" - )) - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MustUseNoEffect { article, target }, + ); } // For now, its always valid @@ -1297,11 +1112,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Struct | Target::Enum | Target::Union | Target::Trait => true, _ => { - self.tcx - .sess - .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait") - .span_label(span, "is not a struct, enum, or trait") - .emit(); + self.tcx.sess.emit_err(errors::MustNotSuspend { attr_span: attr.span, span }); false } } @@ -1321,16 +1132,12 @@ impl CheckAttrVisitor<'_> { _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used // this, so only emit a warning. - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - lint.build("attribute should be applied to a function") - .warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ) - .span_label(span, "not a function") - .emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::Cold { span }, + ); } } } @@ -1345,19 +1152,12 @@ impl CheckAttrVisitor<'_> { return; } - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - let mut diag = - lint.build("attribute should be applied to an `extern` block with non-Rust ABI"); - diag.warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ); - if target != Target::ForeignMod { - diag.span_label(span, "not an `extern` block"); - } - diag.emit(); - }); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::Link { span: (target != Target::ForeignMod).then_some(span) }, + ); } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. @@ -1628,7 +1428,7 @@ impl CheckAttrVisitor<'_> { /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph /// option is passed to the compiler. fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool { - if self.tcx.sess.opts.debugging_opts.query_dep_graph { + if self.tcx.sess.opts.unstable_opts.query_dep_graph { true } else { self.tcx @@ -1811,21 +1611,6 @@ impl CheckAttrVisitor<'_> { _ => ("a", "struct, enum, or union"), } } - sym::no_niche => { - if !self.tcx.features().enabled(sym::no_niche) { - feature_err( - &self.tcx.sess.parse_sess, - sym::no_niche, - hint.span(), - "the attribute `repr(no_niche)` is currently unstable", - ) - .emit(); - } - match target { - Target::Struct | Target::Enum => continue, - _ => ("a", "struct or enum"), - } - } sym::i8 | sym::u8 | sym::i16 @@ -1873,10 +1658,8 @@ impl CheckAttrVisitor<'_> { // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. let hint_spans = hints.iter().map(|hint| hint.span()); - // Error on repr(transparent, <anything else apart from no_niche>). - let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche; - let non_no_niche_count = hints.iter().filter(non_no_niche).count(); - if is_transparent && non_no_niche_count > 1 { + // Error on repr(transparent, <anything else>). + if is_transparent && hints.len() > 1 { let hint_spans: Vec<_> = hint_spans.clone().collect(); struct_span_err!( self.tcx.sess, @@ -2431,7 +2214,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let check_attr_visitor = &mut CheckAttrVisitor { tcx }; - tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor); + tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor); if module_def_id.is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 996ca66de0e45..f1a81b65329af 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -56,7 +56,7 @@ impl NonConstExpr { fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let mut vis = CheckConstVisitor::new(tcx); - tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis); } pub(crate) fn provide(providers: &mut Providers) { @@ -122,7 +122,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a // corresponding feature gate. This encourages nightly users to use feature gates when // possible. - None if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => { + None if tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you => { tcx.sess.span_warn(span, "skipping const checks"); return; } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 01d93f6ff0c08..58c5e5b4dfe53 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -10,14 +10,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; -use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; use std::mem; // Any local node that may call something in its body block should be @@ -82,8 +80,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, _) => { - self.check_def_id(res.def_id()); + Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => { + self.check_def_id(def_id); } _ if self.in_pat => {} Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} @@ -102,6 +100,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.check_def_id(variant_id); } } + Res::Def(_, def_id) => self.check_def_id(def_id), Res::SelfTy { trait_: t, alias_to: i } => { if let Some(t) = t { self.check_def_id(t); @@ -111,9 +110,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} - _ => { - self.check_def_id(res.def_id()); - } } } @@ -285,20 +281,33 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { let def = self.tcx.adt_def(item.def_id); self.repr_has_repr_c = def.repr().c(); - intravisit::walk_item(self, &item); - } - hir::ItemKind::Enum(..) => { - intravisit::walk_item(self, &item); + intravisit::walk_item(self, &item) } hir::ItemKind::ForeignMod { .. } => {} - _ => { - intravisit::walk_item(self, &item); - } + _ => intravisit::walk_item(self, &item), }, Node::TraitItem(trait_item) => { intravisit::walk_trait_item(self, trait_item); } Node::ImplItem(impl_item) => { + let item = self.tcx.local_parent(impl_item.def_id); + if self.tcx.impl_trait_ref(item).is_none() { + //// If it's a type whose items are live, then it's live, too. + //// This is done to handle the case where, for example, the static + //// method of a private type is used, but the type itself is never + //// called directly. + let self_ty = self.tcx.type_of(item); + match *self_ty.kind() { + ty::Adt(def, _) => self.check_def_id(def.did()), + ty::Foreign(did) => self.check_def_id(did), + ty::Dynamic(data, ..) => { + if let Some(def_id) = data.principal_def_id() { + self.check_def_id(def_id) + } + } + _ => {} + } + } intravisit::walk_impl_item(self, impl_item); } Node::ForeignItem(foreign_item) => { @@ -624,8 +633,7 @@ fn live_symbols_and_ignored_derived_traits<'tcx>( } struct DeadVariant { - hir_id: hir::HirId, - span: Span, + def_id: LocalDefId, name: Symbol, level: lint::Level, } @@ -637,85 +645,53 @@ struct DeadVisitor<'tcx> { } impl<'tcx> DeadVisitor<'tcx> { - fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool { - let should_warn = matches!( - item.kind, - hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - ); - should_warn && !self.symbol_is_live(item.def_id) - } - - fn should_warn_about_field(&mut self, field: &hir::FieldDef<'_>) -> bool { - let def_id = self.tcx.hir().local_def_id(field.hir_id); - let field_type = self.tcx.type_of(def_id); - !field.is_positional() - && !self.symbol_is_live(def_id) - && !field_type.is_phantom_data() - && !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id) - } - - fn should_warn_about_variant(&mut self, variant: &hir::Variant<'_>) -> bool { - let def_id = self.tcx.hir().local_def_id(variant.id); - !self.symbol_is_live(def_id) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.id) - } - - fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem<'_>) -> bool { - !self.symbol_is_live(fi.def_id) && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id()) - } - - // id := HIR id of an item's definition. - fn symbol_is_live(&mut self, def_id: LocalDefId) -> bool { - if self.live_symbols.contains(&def_id) { - return true; + fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> bool { + if self.live_symbols.contains(&field.did.expect_local()) { + return false; } - // If it's a type whose items are live, then it's live, too. - // This is done to handle the case where, for example, the static - // method of a private type is used, but the type itself is never - // called directly. - let inherent_impls = self.tcx.inherent_impls(def_id); - for &impl_did in inherent_impls.iter() { - for item_did in self.tcx.associated_item_def_ids(impl_did) { - if let Some(def_id) = item_did.as_local() - && self.live_symbols.contains(&def_id) - { - return true; - } - } + let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit()); + if is_positional { + return false; } - false + let field_type = self.tcx.type_of(field.did); + !field_type.is_phantom_data() } fn warn_multiple_dead_codes( &self, - dead_codes: &[(hir::HirId, Span, Symbol)], + dead_codes: &[LocalDefId], participle: &str, - parent_hir_id: Option<hir::HirId>, + parent_item: Option<LocalDefId>, ) { - if let Some((id, _, name)) = dead_codes.first() - && !name.as_str().starts_with('_') - { - self.tcx.struct_span_lint_hir( + if let Some(&first_id) = dead_codes.first() { + let tcx = self.tcx; + let names: Vec<_> = dead_codes + .iter() + .map(|&def_id| tcx.item_name(def_id.to_def_id()).to_string()) + .collect(); + let spans = dead_codes + .iter() + .map(|&def_id| match tcx.def_ident_span(def_id) { + Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()), + None => tcx.def_span(def_id), + }) + .collect(); + + tcx.struct_span_lint_hir( lint::builtin::DEAD_CODE, - *id, - MultiSpan::from_spans( - dead_codes.iter().map(|(_, span, _)| *span).collect(), - ), + tcx.hir().local_def_id_to_hir_id(first_id), + MultiSpan::from_spans(spans), |lint| { - let def_id = self.tcx.hir().local_def_id(*id); - let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); + let descr = tcx.def_kind(first_id).descr(first_id.to_def_id()); let span_len = dead_codes.len(); - let names = match &dead_codes.iter().map(|(_, _, n)| n.to_string()).collect::<Vec<_>>()[..] - { + let names = match &names[..] { _ if span_len > 6 => String::new(), [name] => format!("`{name}` "), [names @ .., last] => { - format!("{} and `{last}` ", names.iter().map(|name| format!("`{name}`")).join(", ")) + format!( + "{} and `{last}` ", + names.iter().map(|name| format!("`{name}`")).join(", ") + ) } [] => unreachable!(), }; @@ -725,25 +701,17 @@ impl<'tcx> DeadVisitor<'tcx> { s = pluralize!(span_len), are = pluralize!("is", span_len), )); - let hir = self.tcx.hir(); - if let Some(parent_hir_id) = parent_hir_id - && let Some(parent_node) = hir.find(parent_hir_id) - && let Node::Item(item) = parent_node - { - let def_id = self.tcx.hir().local_def_id(parent_hir_id); - let parent_descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); + + if let Some(parent_item) = parent_item { + let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id()); err.span_label( - item.ident.span, - format!( - "{descr}{s} in this {parent_descr}", - s = pluralize!(span_len) - ), + tcx.def_ident_span(parent_item).unwrap(), + format!("{descr}{s} in this {parent_descr}", s = pluralize!(span_len)), ); } - if let Some(encl_scope) = hir.get_enclosing_scope(*id) - && let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) - && let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) - { + + let encl_def_id = parent_item.unwrap_or(first_id); + if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) { let traits_str = ign_traits .iter() .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id))) @@ -764,15 +732,15 @@ impl<'tcx> DeadVisitor<'tcx> { ); err.note(&msg); } - err.emit(); - }, + err.emit(); + }, ); } } fn warn_dead_fields_and_variants( &self, - hir_id: hir::HirId, + def_id: LocalDefId, participle: &str, dead_codes: Vec<DeadVariant>, ) { @@ -787,207 +755,110 @@ impl<'tcx> DeadVisitor<'tcx> { dead_codes.sort_by_key(|v| v.level); for (_, group) in &dead_codes.into_iter().group_by(|v| v.level) { self.warn_multiple_dead_codes( - &group - .map(|v| (v.hir_id, v.span, v.name)) - .collect::<Vec<(hir::HirId, Span, Symbol)>>(), + &group.map(|v| v.def_id).collect::<Vec<_>>(), participle, - Some(hir_id), + Some(def_id), ); } } - fn warn_dead_code( - &mut self, - id: hir::HirId, - span: rustc_span::Span, - name: Symbol, - participle: &str, - ) { - self.warn_multiple_dead_codes(&[(id, span, name)], participle, None); + fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) { + self.warn_multiple_dead_codes(&[id], participle, None); } -} -impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> { - type NestedFilter = nested_filter::All; - - /// Walk nested items in place so that we don't report dead-code - /// on inner functions when the outer function is already getting - /// an error. We could do this also by checking the parents, but - /// this is how the code is setup and it seems harmless enough. - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - if self.should_warn_about_item(item) { - // For most items, we want to highlight its identifier - let span = match item.kind { - hir::ItemKind::Fn(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::Trait(..) - | hir::ItemKind::Impl { .. } => { - // FIXME(66095): Because item.span is annotated with things - // like expansion data, and ident.span isn't, we use the - // def_span method if it's part of a macro invocation - // (and thus has a source_callee set). - // We should probably annotate ident.span with the macro - // context, but that's a larger change. - if item.span.source_callee().is_some() { - self.tcx.sess.source_map().guess_head_span(item.span) - } else { - item.ident.span - } - } - _ => item.span, - }; - let participle = match item.kind { - hir::ItemKind::Struct(..) => "constructed", // Issue #52325 - _ => "used", - }; - self.warn_dead_code(item.hir_id(), span, item.ident.name, participle); - } else { - // Only continue if we didn't warn - intravisit::walk_item(self, item); + fn check_definition(&mut self, def_id: LocalDefId) { + if self.live_symbols.contains(&def_id) { + return; + } + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + if has_allow_dead_code_or_lang_attr(self.tcx, hir_id) { + return; + } + let Some(name) = self.tcx.opt_item_name(def_id.to_def_id()) else { + return + }; + if name.as_str().starts_with('_') { + return; + } + match self.tcx.def_kind(def_id) { + DefKind::AssocConst + | DefKind::AssocFn + | DefKind::Fn + | DefKind::Static(_) + | DefKind::Const + | DefKind::TyAlias + | DefKind::Enum + | DefKind::Union + | DefKind::ForeignTy => self.warn_dead_code(def_id, "used"), + DefKind::Struct => self.warn_dead_code(def_id, "constructed"), + DefKind::Variant | DefKind::Field => bug!("should be handled specially"), + _ => {} } } +} - // This visitor should only visit a single module at a time. - fn visit_mod(&mut self, _: &'tcx hir::Mod<'tcx>, _: Span, _: hir::HirId) {} +fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { + let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(()); + let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits }; - fn visit_enum_def( - &mut self, - enum_definition: &'tcx hir::EnumDef<'tcx>, - generics: &'tcx hir::Generics<'tcx>, - item_id: hir::HirId, - _: Span, - ) { - intravisit::walk_enum_def(self, enum_definition, generics, item_id); - let dead_variants = enum_definition - .variants - .iter() - .filter_map(|variant| { - if self.should_warn_about_variant(&variant) { - Some(DeadVariant { - hir_id: variant.id, - span: variant.span, - name: variant.ident.name, - level: self.tcx.lint_level_at_node(lint::builtin::DEAD_CODE, variant.id).0, - }) - } else { - None - } - }) - .collect(); - self.warn_dead_fields_and_variants(item_id, "constructed", dead_variants) - } + let module_items = tcx.hir_module_items(module); - fn visit_variant( - &mut self, - variant: &'tcx hir::Variant<'tcx>, - g: &'tcx hir::Generics<'tcx>, - id: hir::HirId, - ) { - if !self.should_warn_about_variant(&variant) { - intravisit::walk_variant(self, variant, g, id); + for item in module_items.items() { + if !live_symbols.contains(&item.def_id) { + let parent = tcx.local_parent(item.def_id); + if parent != module && !live_symbols.contains(&parent) { + // We already have diagnosed something. + continue; + } + visitor.check_definition(item.def_id); + continue; } - } - fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem<'tcx>) { - if self.should_warn_about_foreign_item(fi) { - self.warn_dead_code(fi.hir_id(), fi.span, fi.ident.name, "used"); - } - intravisit::walk_foreign_item(self, fi); - } + let def_kind = tcx.def_kind(item.def_id); + if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind { + let adt = tcx.adt_def(item.def_id); + let mut dead_variants = Vec::new(); - fn visit_variant_data( - &mut self, - def: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &hir::Generics<'_>, - id: hir::HirId, - _: rustc_span::Span, - ) { - intravisit::walk_struct_def(self, def); - let dead_fields = def - .fields() - .iter() - .filter_map(|field| { - if self.should_warn_about_field(&field) { - Some(DeadVariant { - hir_id: field.hir_id, - span: field.span, - name: field.ident.name, - level: self - .tcx - .lint_level_at_node(lint::builtin::DEAD_CODE, field.hir_id) - .0, - }) - } else { - None + for variant in adt.variants() { + let def_id = variant.def_id.expect_local(); + if !live_symbols.contains(&def_id) { + // Record to group diagnostics. + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; + dead_variants.push(DeadVariant { def_id, name: variant.name, level }); + continue; } - }) - .collect(); - self.warn_dead_fields_and_variants(id, "read", dead_fields) - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - match impl_item.kind { - hir::ImplItemKind::Const(_, body_id) => { - if !self.symbol_is_live(impl_item.def_id) { - self.warn_dead_code( - impl_item.hir_id(), - impl_item.span, - impl_item.ident.name, - "used", - ); - } - self.visit_nested_body(body_id) - } - hir::ImplItemKind::Fn(_, body_id) => { - if !self.symbol_is_live(impl_item.def_id) { - // FIXME(66095): Because impl_item.span is annotated with things - // like expansion data, and ident.span isn't, we use the - // def_span method if it's part of a macro invocation - // (and thus has a source_callee set). - // We should probably annotate ident.span with the macro - // context, but that's a larger change. - let span = if impl_item.span.source_callee().is_some() { - self.tcx.sess.source_map().guess_head_span(impl_item.span) - } else { - impl_item.ident.span - }; - self.warn_dead_code(impl_item.hir_id(), span, impl_item.ident.name, "used"); - } - self.visit_nested_body(body_id) + + let dead_fields = variant + .fields + .iter() + .filter_map(|field| { + let def_id = field.did.expect_local(); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + if visitor.should_warn_about_field(&field) { + let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; + Some(DeadVariant { def_id, name: field.name, level }) + } else { + None + } + }) + .collect(); + visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields) } - hir::ImplItemKind::TyAlias(..) => {} + + visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants); } } - // Overwrite so that we don't warn the trait item itself. - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - match trait_item.kind { - hir::TraitItemKind::Const(_, Some(body_id)) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => { - self.visit_nested_body(body_id) - } - hir::TraitItemKind::Const(_, None) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) - | hir::TraitItemKind::Type(..) => {} - } + for impl_item in module_items.impl_items() { + visitor.check_definition(impl_item.def_id); } -} -fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { - let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(()); - let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits }; - let (module, _, module_id) = tcx.hir().get_module(module); - // Do not use an ItemLikeVisitor since we may want to skip visiting some items - // when a surrounding one is warned against or `_`. - intravisit::walk_mod(&mut visitor, module, module_id); + for foreign_item in module_items.foreign_items() { + visitor.check_definition(foreign_item.def_id); + } + + // We do not warn trait items. } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index f9e67310452a7..1add91fc9c531 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,4 +1,4 @@ -use rustc_ast::entry::EntryPointType; +use rustc_ast::{entry::EntryPointType, Attribute}; use rustc_errors::struct_span_err; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -7,9 +7,8 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{DefIdTree, TyCtxt}; use rustc_session::config::{CrateType, EntryFnType}; use rustc_session::parse::feature_err; -use rustc_session::Session; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{Span, Symbol, DUMMY_SP}; struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -72,9 +71,16 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry } } -fn throw_attr_err(sess: &Session, span: Span, attr: &str) { - sess.struct_span_err(span, &format!("`{}` attribute can only be used on functions", attr)) - .emit(); +fn err_if_attr_found(ctxt: &EntryContext<'_>, attrs: &[Attribute], sym: Symbol) { + if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) { + ctxt.tcx + .sess + .struct_span_err( + attr.span, + &format!("`{}` attribute can only be used on functions", sym.as_str()), + ) + .emit(); + } } fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { @@ -84,12 +90,8 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { EntryPointType::None => (), _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) { - throw_attr_err(&ctxt.tcx.sess, attr.span, "start"); - } - if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::rustc_main) { - throw_attr_err(&ctxt.tcx.sess, attr.span, "rustc_main"); - } + err_if_attr_found(ctxt, attrs, sym::start); + err_if_attr_found(ctxt, attrs, sym::rustc_main); } EntryPointType::MainNamed => (), EntryPointType::OtherMain => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs new file mode 100644 index 0000000000000..f8e8720ab5474 --- /dev/null +++ b/compiler/rustc_passes/src/errors.rs @@ -0,0 +1,362 @@ +use rustc_errors::{Applicability, MultiSpan}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(LintDiagnostic)] +#[lint(passes::outer_crate_level_attr)] +pub struct OuterCrateLevelAttr; + +#[derive(LintDiagnostic)] +#[lint(passes::inner_crate_level_attr)] +pub struct InnerCrateLevelAttr; + +#[derive(LintDiagnostic)] +#[lint(passes::ignored_attr_with_macro)] +pub struct IgnoredAttrWithMacro<'a> { + pub sym: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::ignored_attr)] +pub struct IgnoredAttr<'a> { + pub sym: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::inline_ignored_function_prototype)] +pub struct IgnoredInlineAttrFnProto; + +#[derive(LintDiagnostic)] +#[lint(passes::inline_ignored_constants)] +#[warn_] +#[note] +pub struct IgnoredInlineAttrConstants; + +#[derive(SessionDiagnostic)] +#[error(passes::inline_not_fn_or_closure, code = "E0518")] +pub struct InlineNotFnOrClosure { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::no_coverage_ignored_function_prototype)] +pub struct IgnoredNoCoverageFnProto; + +#[derive(LintDiagnostic)] +#[lint(passes::no_coverage_propagate)] +pub struct IgnoredNoCoveragePropagate; + +#[derive(LintDiagnostic)] +#[lint(passes::no_coverage_fn_defn)] +pub struct IgnoredNoCoverageFnDefn; + +#[derive(SessionDiagnostic)] +#[error(passes::no_coverage_not_coverable, code = "E0788")] +pub struct IgnoredNoCoverageNotCoverable { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_fn)] +pub struct AttrShouldBeAppliedToFn { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::naked_tracked_caller, code = "E0736")] +pub struct NakedTrackedCaller { + #[primary_span] + pub attr_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_fn, code = "E0739")] +pub struct TrackedCallerWrongLocation { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_struct_enum, code = "E0701")] +pub struct NonExhaustiveWrongLocation { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_trait)] +pub struct AttrShouldBeAppliedToTrait { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::target_feature_on_statement)] +pub struct TargetFeatureOnStatement; + +#[derive(SessionDiagnostic)] +#[error(passes::should_be_applied_to_static)] +pub struct AttrShouldBeAppliedToStatic { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_expect_str)] +pub struct DocExpectStr<'a> { + #[primary_span] + pub attr_span: Span, + pub attr_name: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_empty)] +pub struct DocAliasEmpty<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_bad_char)] +pub struct DocAliasBadChar<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, + pub char_: char, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_start_end)] +pub struct DocAliasStartEnd<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_bad_location)] +pub struct DocAliasBadLocation<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, + pub location: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_not_an_alias)] +pub struct DocAliasNotAnAlias<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_alias_duplicated)] +pub struct DocAliasDuplicated { + #[label] + pub first_defn: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_not_string_literal)] +pub struct DocAliasNotStringLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_alias_malformed)] +pub struct DocAliasMalformed { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_empty_mod)] +pub struct DocKeywordEmptyMod { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_not_mod)] +pub struct DocKeywordNotMod { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_invalid_ident)] +pub struct DocKeywordInvalidIdent { + #[primary_span] + pub span: Span, + pub doc_keyword: Symbol, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_tuple_variadic_not_first)] +pub struct DocTupleVariadicNotFirst { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_keyword_only_impl)] +pub struct DocKeywordOnlyImpl { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_inline_conflict)] +#[help] +pub struct DocKeywordConflict { + #[primary_span] + pub spans: MultiSpan, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_inline_only_use)] +#[note] +pub struct DocInlineOnlyUse { + #[label] + pub attr_span: Span, + #[label(passes::not_a_use_item_label)] + pub item_span: Option<Span>, +} + +#[derive(SessionDiagnostic)] +#[error(passes::doc_attr_not_crate_level)] +pub struct DocAttrNotCrateLevel<'a> { + #[primary_span] + pub span: Span, + pub attr_name: &'a str, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown)] +pub struct DocTestUnknown { + pub path: String, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_takes_list)] +pub struct DocTestTakesList; + +#[derive(LintDiagnostic)] +#[lint(passes::doc_primitive)] +pub struct DocPrimitive; + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown_any)] +pub struct DocTestUnknownAny { + pub path: String, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown_spotlight)] +#[note] +#[note(passes::no_op_note)] +pub struct DocTestUnknownSpotlight { + pub path: String, + #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_test_unknown_include)] +pub struct DocTestUnknownInclude { + pub path: String, + pub value: String, + pub inner: &'static str, + #[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")] + pub sugg: (Span, Applicability), +} + +#[derive(LintDiagnostic)] +#[lint(passes::doc_invalid)] +pub struct DocInvalid; + +#[derive(SessionDiagnostic)] +#[error(passes::pass_by_value)] +pub struct PassByValue { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::allow_incoherent_impl)] +pub struct AllowIncoherentImpl { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(passes::has_incoherent_inherent_impl)] +pub struct HasIncoherentInherentImpl { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::must_use_async)] +pub struct MustUseAsync { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::must_use_no_effect)] +pub struct MustUseNoEffect { + pub article: &'static str, + pub target: rustc_hir::Target, +} + +#[derive(SessionDiagnostic)] +#[error(passes::must_not_suspend)] +pub struct MustNotSuspend { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::cold)] +#[warn_] +pub struct Cold { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(passes::link)] +#[warn_] +pub struct Link { + #[label] + pub span: Option<Span>, +} diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 23ff0a9115970..212ea9e57a37b 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -1,9 +1,9 @@ -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lock; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit; use rustc_hir::{HirId, ItemLocalId}; +use rustc_index::bit_set::GrowableBitSet; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; @@ -11,36 +11,39 @@ use rustc_middle::ty::TyCtxt; pub fn check_crate(tcx: TyCtxt<'_>) { tcx.dep_graph.assert_ignored(); - if tcx.sess.opts.debugging_opts.hir_stats { + if tcx.sess.opts.unstable_opts.hir_stats { crate::hir_stats::print_hir_stats(tcx); } - let errors = Lock::new(Vec::new()); - let hir_map = tcx.hir(); + #[cfg(debug_assertions)] + { + let errors = Lock::new(Vec::new()); + let hir_map = tcx.hir(); - hir_map.par_for_each_module(|module_id| { - let mut v = HirIdValidator { - hir_map, - owner: None, - hir_ids_seen: Default::default(), - errors: &errors, - }; + hir_map.par_for_each_module(|module_id| { + let mut v = HirIdValidator { + hir_map, + owner: None, + hir_ids_seen: Default::default(), + errors: &errors, + }; - tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v); - }); + tcx.hir().visit_item_likes_in_module(module_id, &mut v); + }); - let errors = errors.into_inner(); + let errors = errors.into_inner(); - if !errors.is_empty() { - let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message); + if !errors.is_empty() { + let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); + tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message); + } } } struct HirIdValidator<'a, 'hir> { hir_map: Map<'hir>, owner: Option<LocalDefId>, - hir_ids_seen: FxHashSet<ItemLocalId>, + hir_ids_seen: GrowableBitSet<ItemLocalId>, errors: &'a Lock<Vec<String>>, } @@ -80,7 +83,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { if max != self.hir_ids_seen.len() - 1 { // Collect the missing ItemLocalIds let missing: Vec<_> = (0..=max as u32) - .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i))) + .filter(|&i| !self.hir_ids_seen.contains(ItemLocalId::from_u32(i))) .collect(); // Try to map those to something more useful @@ -106,7 +109,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { missing_items, self.hir_ids_seen .iter() - .map(|&local_id| HirId { owner, local_id }) + .map(|local_id| HirId { owner, local_id }) .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h))) .collect::<Vec<_>>() ) diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 497c0931c2182..defa9d15296e0 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -7,8 +7,8 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(iter_intersperse)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(try_blocks)] @@ -27,6 +27,7 @@ pub mod dead; mod debugger_visualizer; mod diagnostic_items; pub mod entry; +mod errors; pub mod hir_id_validator; pub mod hir_stats; mod lang_items; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 80a263f4cb2dd..eed3e1579a231 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { } fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx)); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx)); } pub fn provide(providers: &mut Providers) { @@ -278,7 +278,7 @@ impl<'tcx> IrMaps<'tcx> { pats.extend(inner_pat.iter()); } Struct(_, fields, _) => { - let (short, not_short): (Vec<&_>, Vec<&_>) = + let (short, not_short): (Vec<_>, _) = fields.iter().partition(|f| f.is_shorthand); shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id)); pats.extend(not_short.iter().map(|f| f.pat)); @@ -298,7 +298,7 @@ impl<'tcx> IrMaps<'tcx> { } } - return shorthand_field_ids; + shorthand_field_ids } fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { @@ -368,6 +368,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { self.add_from_pat(&local.pat); + if local.els.is_some() { + self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id)); + } intravisit::walk_local(self, local); } @@ -800,8 +803,40 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // initialization, which is mildly more complex than checking // once at the func header but otherwise equivalent. - let succ = self.propagate_through_opt_expr(local.init, succ); - self.define_bindings_in_pat(&local.pat, succ) + if let Some(els) = local.els { + // Eventually, `let pat: ty = init else { els };` is mostly equivalent to + // `let (bindings, ...) = match init { pat => (bindings, ...), _ => els };` + // except that extended lifetime applies at the `init` location. + // + // (e) + // | + // v + // (expr) + // / \ + // | | + // v v + // bindings els + // | + // v + // ( succ ) + // + if let Some(init) = local.init { + let else_ln = self.propagate_through_block(els, succ); + let ln = self.live_node(local.hir_id, local.span); + self.init_from_succ(ln, succ); + self.merge_from_succ(ln, else_ln); + let succ = self.propagate_through_expr(init, ln); + self.define_bindings_in_pat(&local.pat, succ) + } else { + span_bug!( + stmt.span, + "variable is uninitialized but an unexpected else branch is found" + ) + } + } else { + let succ = self.propagate_through_opt_expr(local.init, succ); + self.define_bindings_in_pat(&local.pat, succ) + } } hir::StmtKind::Item(..) => succ, hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { @@ -1121,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // (rvalue) || (rvalue) // | || | // v || v - // (write of place) || (place components) + // (write of place) || (place components) // | || | // v || v // (succ) || (succ) diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 9cfef26fd0310..cdda0e388ddf0 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -31,7 +31,7 @@ struct CheckLoopVisitor<'a, 'hir> { } fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().deep_visit_item_likes_in_module( + tcx.hir().visit_item_likes_in_module( module_def_id, &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }, ); @@ -57,7 +57,13 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Loop(ref b, _, source, _) => { self.with_context(Loop(source), |v| v.visit_block(&b)); } - hir::ExprKind::Closure { ref fn_decl, body, fn_decl_span, movability, .. } => { + hir::ExprKind::Closure(&hir::Closure { + ref fn_decl, + body, + fn_decl_span, + movability, + .. + }) => { let cx = if let Some(Movability::Static) = movability { AsyncClosure(fn_decl_span) } else { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 40844b84af079..20765abf39280 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -14,7 +14,7 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx }); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx }); } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index c830ab11e8e6e..f7e3fac6b2e20 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -273,7 +273,10 @@ impl<'tcx> ReachableContext<'tcx> { } hir::ImplItemKind::TyAlias(_) => {} }, - Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) => { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), + .. + }) => { self.visit_nested_body(body); } // Nothing to recurse on for these diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9eaefc8b8aa8f..4e091c5b70d5c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,6 +1,7 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. +use attr::StabilityLevel; use rustc_attr::{self as attr, ConstStability, Stability}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::struct_span_err; @@ -13,13 +14,12 @@ use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; -use rustc_middle::ty::{self, query::Providers, TyCtxt}; +use rustc_middle::ty::{query::Providers, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; -use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_target::spec::abi::Abi; use std::cmp::Ordering; @@ -224,7 +224,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. - if let (&Some(dep_since), &attr::Stable { since: stab_since }) = + if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) = (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) { // Explicit version of iter::order::lt to handle parse errors properly @@ -628,7 +628,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { // compiling `librustc_*` crates themselves so we can leverage crates.io // while maintaining the invariant that all sysroot crates are unstable // by default and are unable to be used. - if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { let reason = "this crate is being loaded from the sysroot, an \ unstable location; did you mean to load this crate \ from crates.io via `Cargo.toml` instead?"; @@ -660,7 +660,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { /// Cross-references the feature names of unstable APIs with enabled /// features and possibly prints errors. fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); } pub(crate) fn provide(providers: &mut Providers) { @@ -766,39 +766,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - // There's no good place to insert stability check for non-Copy unions, - // so semi-randomly perform it here in stability.rs - hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { - let ty = self.tcx.type_of(item.def_id); - let ty::Adt(adt_def, substs) = ty.kind() else { bug!() }; - - // Non-`Copy` fields are unstable, except for `ManuallyDrop`. - let param_env = self.tcx.param_env(item.def_id); - for field in &adt_def.non_enum_variant().fields { - let field_ty = field.ty(self.tcx, substs); - if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) - && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env) - { - if field_ty.needs_drop(self.tcx, param_env) { - // Avoid duplicate error: This will error later anyway because fields - // that need drop are not allowed. - self.tcx.sess.delay_span_bug( - item.span, - "union should have been rejected due to potentially dropping field", - ); - } else { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - self.tcx.def_span(field.did), - "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable", - ) - .emit(); - } - } - } - } - _ => (/* pass */), } intravisit::walk_item(self, item); @@ -807,7 +774,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) { if let Some(def_id) = path.res.opt_def_id() { let method_span = path.segments.last().map(|s| s.ident.span); - self.tcx.check_stability_allow_unstable( + let item_is_allowed = self.tcx.check_stability_allow_unstable( def_id, Some(id), path.span, @@ -817,8 +784,52 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } else { AllowUnstable::No }, - ) + ); + + let is_allowed_through_unstable_modules = |def_id| { + self.tcx + .lookup_stability(def_id) + .map(|stab| match stab.level { + StabilityLevel::Stable { allowed_through_unstable_modules, .. } => { + allowed_through_unstable_modules + } + _ => false, + }) + .unwrap_or(false) + }; + + if item_is_allowed && !is_allowed_through_unstable_modules(def_id) { + // Check parent modules stability as well if the item the path refers to is itself + // stable. We only emit warnings for unstable path segments if the item is stable + // or allowed because stability is often inherited, so the most common case is that + // both the segments and the item are unstable behind the same feature flag. + // + // We check here rather than in `visit_path_segment` to prevent visiting the last + // path segment twice + // + // We include special cases via #[rustc_allowed_through_unstable_modules] for items + // that were accidentally stabilized through unstable paths before this check was + // added, such as `core::intrinsics::transmute` + let parents = path.segments.iter().rev().skip(1); + for path_segment in parents { + if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) { + // use `None` for id to prevent deprecation check + self.tcx.check_stability_allow_unstable( + def_id, + None, + path.span, + None, + if is_unstable_reexport(self.tcx, id) { + AllowUnstable::Yes + } else { + AllowUnstable::No + }, + ); + } + } + } } + intravisit::walk_path(self, path) } } @@ -884,13 +895,13 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let is_staged_api = - tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api; + tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api; if is_staged_api { let access_levels = &tcx.privacy_access_levels(()); let mut missing = MissingStabilityAnnotations { tcx, access_levels }; missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); tcx.hir().walk_toplevel_module(&mut missing); - tcx.hir().deep_visit_all_item_likes(&mut missing); + tcx.hir().visit_all_item_likes_in_crate(&mut missing); } let declared_lang_features = &tcx.features().declared_lang_features; diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index d952e288a6477..5785921fb1eda 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -4,14 +4,15 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_middle = { path = "../rustc_middle" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } -rustc_typeck = { path = "../rustc_typeck" } +rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_data_structures = { path = "../rustc_data_structures" } rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_typeck = { path = "../rustc_typeck" } tracing = "0.1" diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs new file mode 100644 index 0000000000000..b0fac91f6ebc3 --- /dev/null +++ b/compiler/rustc_privacy/src/errors.rs @@ -0,0 +1,91 @@ +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[error(privacy::field_is_private, code = "E0451")] +pub struct FieldIsPrivate { + #[primary_span] + pub span: Span, + pub field_name: Symbol, + pub variant_descr: &'static str, + pub def_path_str: String, + #[subdiagnostic] + pub label: FieldIsPrivateLabel, +} + +#[derive(SessionSubdiagnostic)] +pub enum FieldIsPrivateLabel { + #[label(privacy::field_is_private_is_update_syntax_label)] + IsUpdateSyntax { + #[primary_span] + span: Span, + field_name: Symbol, + }, + #[label(privacy::field_is_private_label)] + Other { + #[primary_span] + span: Span, + }, +} + +#[derive(SessionDiagnostic)] +#[error(privacy::item_is_private)] +pub struct ItemIsPrivate<'a> { + #[primary_span] + #[label] + pub span: Span, + pub kind: &'a str, + pub descr: String, +} + +#[derive(SessionDiagnostic)] +#[error(privacy::unnamed_item_is_private)] +pub struct UnnamedItemIsPrivate { + #[primary_span] + pub span: Span, + pub kind: &'static str, +} + +// Duplicate of `InPublicInterface` but with a different error code, shares the same slug. +#[derive(SessionDiagnostic)] +#[error(privacy::in_public_interface, code = "E0445")] +pub struct InPublicInterfaceTraits<'a> { + #[primary_span] + #[label] + pub span: Span, + pub vis_descr: &'static str, + pub kind: &'a str, + pub descr: String, + #[label(privacy::visibility_label)] + pub vis_span: Span, +} + +// Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug. +#[derive(SessionDiagnostic)] +#[error(privacy::in_public_interface, code = "E0446")] +pub struct InPublicInterface<'a> { + #[primary_span] + #[label] + pub span: Span, + pub vis_descr: &'static str, + pub kind: &'a str, + pub descr: String, + #[label(privacy::visibility_label)] + pub vis_span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(privacy::from_private_dep_in_public_interface)] +pub struct FromPrivateDependencyInPublicInterface<'a> { + pub kind: &'a str, + pub descr: String, + pub krate: Symbol, +} + +#[derive(LintDiagnostic)] +#[lint(privacy::private_in_public_lint)] +pub struct PrivateInPublicLint<'a> { + pub vis_descr: &'static str, + pub kind: &'a str, + pub descr: String, +} diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index b27c986d0f9da..9a835808d4935 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,15 +1,19 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(associated_type_defaults)] #![feature(control_flow_enum)] +#![feature(rustc_private)] #![feature(try_blocks)] -#![feature(associated_type_defaults)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![cfg_attr(not(bootstrap), deny(rustc::untranslatable_diagnostic))] +#![cfg_attr(not(bootstrap), deny(rustc::diagnostic_outside_of_impl))] + +mod errors; use rustc_ast::MacroDef; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; @@ -19,21 +23,25 @@ use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; use rustc_middle::span_bug; -use rustc_middle::thir::abstract_const::Node as ACNode; +use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind}; -use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; -use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst}; use std::marker::PhantomData; use std::ops::ControlFlow; use std::{cmp, fmt, mem}; +use errors::{ + FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, + InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, UnnamedItemIsPrivate, +}; + //////////////////////////////////////////////////////////////////////////////// /// Generic infrastructure used to implement specific visitors below. //////////////////////////////////////////////////////////////////////////////// @@ -71,7 +79,7 @@ trait DefIdVisitor<'tcx> { dummy: Default::default(), } } - fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit(&mut self, ty_fragment: impl TypeVisitable<'tcx>) -> ControlFlow<Self::BreakTy> { ty_fragment.visit_with(&mut self.skeleton()) } fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -145,6 +153,7 @@ where } ControlFlow::CONTINUE } + ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), _ => bug!("unexpected predicate: {:?}", predicate), } } @@ -154,7 +163,7 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow<V::BreakTy> { - const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) { + walk_abstract_const(tcx, ct, |node| match node.root(tcx) { ACNode::Leaf(leaf) => self.visit_const(leaf), ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { @@ -457,7 +466,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { } let macro_module_def_id = self.tcx.local_parent(local_def_id); - if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) { + if self.tcx.opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) { // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252). return; } @@ -935,23 +944,17 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; if !field.vis.is_accessible_from(def_id, self.tcx) { - let label = if in_update_syntax { - format!("field `{}` is private", field.name) - } else { - "private field".to_string() - }; - - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(FieldIsPrivate { span, - E0451, - "field `{}` of {} `{}` is private", - field.name, - def.variant_descr(), - self.tcx.def_path_str(def.did()) - ) - .span_label(span, label) - .emit(); + field_name: field.name, + variant_descr: def.variant_descr(), + def_path_str: self.tcx.def_path_str(def.did()), + label: if in_update_syntax { + FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name } + } else { + FieldIsPrivateLabel::Other { span } + }, + }); } } } @@ -1075,11 +1078,11 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { let is_error = !self.item_is_accessible(def_id); if is_error { - self.tcx - .sess - .struct_span_err(self.span, &format!("{} `{}` is private", kind, descr)) - .span_label(self.span, &format!("private {}", kind)) - .emit(); + self.tcx.sess.emit_err(ItemIsPrivate { + span: self.span, + kind, + descr: descr.to_string(), + }); } is_error } @@ -1250,13 +1253,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()), }; let kind = kind.descr(def_id); - let msg = match name { - Some(name) => format!("{} `{}` is private", kind, name), - None => format!("{} is private", kind), + let _ = match name { + Some(name) => sess.emit_err(ItemIsPrivate { span, kind, descr: name }), + None => sess.emit_err(UnnamedItemIsPrivate { span, kind }), }; - sess.struct_span_err(span, &msg) - .span_label(span, &format!("private {}", kind)) - .emit(); return; } } @@ -1716,19 +1716,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { if self.leaks_private_dep(def_id) { - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), self.tcx.def_span(self.item_def_id.to_def_id()), - |lint| { - lint.build(&format!( - "{} `{}` from private dependency '{}' in public \ - interface", - kind, - descr, - self.tcx.crate_name(def_id.krate) - )) - .emit(); + FromPrivateDependencyInPublicInterface { + kind, + descr: descr.to_string(), + krate: self.tcx.crate_name(def_id.krate), }, ); } @@ -1753,31 +1748,38 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } } }; - let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr); let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let descr = descr.to_string(); if self.has_old_errors || self.in_assoc_ty || self.tcx.resolutions(()).has_pub_restricted { - let mut err = if kind == "trait" { - struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg()) - } else { - struct_span_err!(self.tcx.sess, span, E0446, "{}", make_msg()) - }; + let descr = descr.to_string(); let vis_span = self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)); - err.span_label(span, format!("can't leak {} {}", vis_descr, kind)); - err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr)); - err.emit(); + if kind == "trait" { + self.tcx.sess.emit_err(InPublicInterfaceTraits { + span, + vis_descr, + kind, + descr, + vis_span, + }); + } else { + self.tcx.sess.emit_err(InPublicInterface { + span, + vis_descr, + kind, + descr, + vis_span, + }); + } } else { - let err_code = if kind == "trait" { "E0445" } else { "E0446" }; - self.tcx.struct_span_lint_hir( + self.tcx.emit_spanned_lint( lint::builtin::PRIVATE_IN_PUBLIC, hir_id, span, - |lint| { - lint.build(&format!("{} (error {})", make_msg(), err_code)).emit(); - }, + PrivateInPublicLint { vis_descr, kind, descr }, ); } } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d06eb97798e73..7c1fdc4e306a4 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -27,6 +27,8 @@ use rustc_span::Span; mod plumbing; pub use plumbing::QueryCtxt; use rustc_query_system::query::*; +#[cfg(parallel_compiler)] +pub use rustc_query_system::query::{deadlock, QueryContext}; mod keys; use keys::Key; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index b01c512a3b439..56fd90c9855e0 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -9,7 +9,6 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; -use rustc_middle::thir; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; @@ -653,12 +652,11 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { #[cfg(debug_assertions)] { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - let mut hcx = decoder.tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - hcx.while_hashing_spans(true, |hcx| { - expn_id.expn_data().hash_stable(hcx, &mut hasher) + let local_hash: u64 = decoder.tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + expn_id.expn_data().hash_stable(&mut hcx, &mut hasher); + hasher.finish() }); - let local_hash: u64 = hasher.finish(); debug_assert_eq!(hash.local_hash(), local_hash); } @@ -767,7 +765,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> } } -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [ty::abstract_const::Node<'tcx>] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 66f4508f6b497..333dc5aa668b0 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -132,11 +132,6 @@ impl<'tcx> QueryCtxt<'tcx> { self.queries.on_disk_cache.as_ref() } - #[cfg(parallel_compiler)] - pub unsafe fn deadlock(self, registry: &rustc_rayon_core::Registry) { - rustc_query_system::query::deadlock(self, registry) - } - pub(super) fn encode_query_results( self, encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>, @@ -287,17 +282,21 @@ macro_rules! define_queries { } else { Some(key.default_span(*tcx)) }; - // Use `tcx.hir().opt_def_kind()` to reduce the chance of - // accidentally triggering an infinite query loop. - let def_kind = key.key_as_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|def_id| tcx.hir().opt_def_kind(def_id)); + let def_kind = if kind == dep_graph::DepKind::opt_def_kind { + // Try to avoid infinite recursion. + None + } else { + key.key_as_def_id() + .and_then(|def_id| def_id.as_local()) + .and_then(|def_id| tcx.opt_def_kind(def_id)) + }; let hash = || { - let mut hcx = tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); - key.hash_stable(&mut hcx, &mut hasher); - hasher.finish::<u64>() + tcx.with_stable_hashing_context(|mut hcx|{ + let mut hasher = StableHasher::new(); + std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); + key.hash_stable(&mut hcx, &mut hasher); + hasher.finish::<u64>() + }) }; QueryStackFrame::new(name, description, span, def_kind, hash) @@ -378,6 +377,17 @@ macro_rules! define_queries { } } + // We use this for the forever-red node. + pub fn Red() -> DepKindStruct { + DepKindStruct { + is_anon: false, + is_eval_always: false, + fingerprint_style: FingerprintStyle::Unit, + force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)), + try_load_from_on_disk_cache: None, + } + } + pub fn TraitSelect() -> DepKindStruct { DepKindStruct { is_anon: true, diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index b5a37cf324b00..b7787aeb8f765 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -22,7 +22,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } parking_lot = "0.11" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } [features] rustc_use_parallel_compiler = ["rustc-rayon-core"] diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index bb2179a24953b..162c274d8a296 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -79,8 +79,8 @@ impl<K: DepKind> DepNode<K> { #[cfg(debug_assertions)] { if !tcx.fingerprint_style(kind).reconstructible() - && (tcx.sess().opts.debugging_opts.incremental_info - || tcx.sess().opts.debugging_opts.query_dep_graph) + && (tcx.sess().opts.unstable_opts.incremental_info + || tcx.sess().opts.unstable_opts.query_dep_graph) { tcx.dep_graph().register_dep_node_debug_str(dep_node, || arg.to_debug_str(tcx)); } @@ -131,12 +131,11 @@ where #[inline(always)] default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { - let mut hcx = tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - self.hash_stable(&mut hcx, &mut hasher); - - hasher.finish() + tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + self.hash_stable(&mut hcx, &mut hasher); + hasher.finish() + }) } #[inline(always)] diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 341cf8f827bc9..8ff56132749df 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -43,6 +43,7 @@ rustc_index::newtype_index! { impl DepNodeIndex { pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0); + pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1); } impl std::convert::From<DepNodeIndex> for QueryInvocationId { @@ -59,6 +60,7 @@ pub enum DepNodeColor { } impl DepNodeColor { + #[inline] pub fn is_green(self) -> bool { match self { DepNodeColor::Red => false, @@ -124,6 +126,8 @@ impl<K: DepKind> DepGraph<K> { record_stats, ); + let colors = DepNodeColorMap::new(prev_graph_node_count); + // Instantiate a dependy-less node only once for anonymous queries. let _green_node_index = current.intern_new_node( profiler, @@ -131,7 +135,19 @@ impl<K: DepKind> DepGraph<K> { smallvec![], Fingerprint::ZERO, ); - debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); + assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); + + // Instantiate a dependy-less red node only once for anonymous queries. + let (_red_node_index, _prev_and_index) = current.intern_node( + profiler, + &prev_graph, + DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, + smallvec![], + None, + false, + ); + assert_eq!(_red_node_index, DepNodeIndex::FOREVER_RED_NODE); + assert!(matches!(_prev_and_index, None | Some((_, DepNodeColor::Red)))); DepGraph { data: Some(Lrc::new(DepGraphData { @@ -140,7 +156,7 @@ impl<K: DepKind> DepGraph<K> { current, processed_side_effects: Default::default(), previous: prev_graph, - colors: DepNodeColorMap::new(prev_graph_node_count), + colors, debug_loaded_from_disk: Default::default(), })), virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), @@ -328,12 +344,10 @@ impl<K: DepKind> DepGraph<K> { let dcx = cx.dep_context(); let hashing_timer = dcx.profiler().incr_result_hashing(); - let current_fingerprint = hash_result.map(|f| { - let mut hcx = dcx.create_stable_hashing_context(); - f(&mut hcx, &result) - }); + let current_fingerprint = + hash_result.map(|f| dcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, &result))); - let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks; + let print_status = cfg!(debug_assertions) && dcx.sess().opts.unstable_opts.dep_tasks; // Intern the new `DepNode`. let (dep_node_index, prev_and_color) = data.current.intern_node( @@ -886,8 +900,12 @@ impl<K: DepKind> DepGraph<K> { #[derive(Clone, Debug, Encodable, Decodable)] pub struct WorkProduct { pub cgu_name: String, - /// Saved file associated with this CGU. - pub saved_file: String, + /// Saved files associated with this CGU. In each key/value pair, the value is the path to the + /// saved file and the key is some identifier for the type of file being saved. + /// + /// By convention, file extensions are currently used as identifiers, i.e. the key "o" maps to + /// the object file's path, and "dwo" to the dwarf object file's path. + pub saved_files: FxHashMap<String, String>, } // Index type for `DepNodeData`'s edges. @@ -967,6 +985,7 @@ impl<K: DepKind> CurrentDepGraph<K> { let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; let mut stable_hasher = StableHasher::new(); nanos.hash(&mut stable_hasher); + let anon_id_seed = stable_hasher.finish(); #[cfg(debug_assertions)] let forbidden_edge = match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { @@ -1002,7 +1021,7 @@ impl<K: DepKind> CurrentDepGraph<K> { ) }), prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), - anon_id_seed: stable_hasher.finish(), + anon_id_seed, #[cfg(debug_assertions)] forbidden_edge, total_read_count: AtomicU64::new(0), diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 5907ae309ca37..342d95ca490ea 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -23,7 +23,7 @@ pub trait DepContext: Copy { type DepKind: self::DepKind; /// Create a hashing context for hashing new results. - fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; + fn with_stable_hashing_context<R>(&self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R; /// Access the DepGraph. fn dep_graph(&self) -> &DepGraph<Self::DepKind>; @@ -85,8 +85,12 @@ impl FingerprintStyle { /// Describe the different families of dependency nodes. pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static { + /// DepKind to use when incr. comp. is turned off. const NULL: Self; + /// DepKind to use to create the initial forever-red node. + const RED: Self; + /// Implementation of `std::fmt::Debug` for `DepNode`. fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result; diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index 62a1f776fb352..217fac341edd6 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -1,4 +1,5 @@ use crate::ich; + use rustc_ast as ast; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; @@ -23,7 +24,7 @@ pub struct StableHashingContext<'a> { cstore: &'a dyn CrateStore, source_span: &'a IndexVec<LocalDefId, Span>, // The value of `-Z incremental-ignore-spans`. - // This field should only be used by `debug_opts_incremental_ignore_span` + // This field should only be used by `unstable_opts_incremental_ignore_span` incremental_ignore_spans: bool, pub(super) body_resolver: BodyResolver<'a>, // Very often, we are hashing something that does not need the @@ -56,14 +57,14 @@ impl<'a> StableHashingContext<'a> { always_ignore_spans: bool, ) -> Self { let hash_spans_initial = - !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans; + !always_ignore_spans && !sess.opts.unstable_opts.incremental_ignore_spans; StableHashingContext { body_resolver: BodyResolver::Forbidden, definitions, cstore, source_span, - incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans, + incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans, caching_source_map: None, raw_source_map: sess.source_map(), hashing_controls: HashingControls { hash_spans: hash_spans_initial }, @@ -118,13 +119,13 @@ impl<'a> StableHashingContext<'a> { &mut self, hash_bodies: bool, owner: LocalDefId, - bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>, - f: impl FnOnce(&mut Self), + bodies: &SortedMap<hir::ItemLocalId, &hir::Body<'_>>, + f: impl FnOnce(&mut StableHashingContext<'_>), ) { - let prev = self.body_resolver; - self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies }; - f(self); - self.body_resolver = prev; + f(&mut StableHashingContext { + body_resolver: BodyResolver::Traverse { hash_bodies, owner, bodies }, + ..self.clone() + }); } #[inline] @@ -185,7 +186,7 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } #[inline] - fn debug_opts_incremental_ignore_spans(&self) -> bool { + fn unstable_opts_incremental_ignore_spans(&self) -> bool { self.incremental_ignore_spans } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 2a07d9b7f809c..9f5779194afcb 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -84,6 +84,7 @@ pub struct QueryJob { impl QueryJob { /// Creates a new query job. + #[inline] pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self { QueryJob { id, @@ -106,6 +107,7 @@ impl QueryJob { /// /// This does nothing for single threaded rustc, /// as there are no concurrent jobs which could be waiting on us + #[inline] pub fn signal_complete(self) { #[cfg(parallel_compiler)] { @@ -492,14 +494,13 @@ fn remove_cycle( /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. #[cfg(parallel_compiler)] -pub fn deadlock<CTX: QueryContext>(tcx: CTX, registry: &rayon_core::Registry) { +pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) { let on_panic = OnDrop(|| { eprintln!("deadlock handler panicked, aborting process"); process::abort(); }); let mut wakelist = Vec::new(); - let query_map = tcx.try_collect_active_jobs().unwrap(); let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect(); let mut found_cycle = false; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index de64ebb620301..f698a853d1e7b 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -81,6 +81,7 @@ pub struct QuerySideEffects { } impl QuerySideEffects { + #[inline] pub fn is_empty(&self) -> bool { let QuerySideEffects { diagnostics } = self; diagnostics.is_empty() diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3e4c7ad9f8f41..792f2b0317357 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -467,7 +467,7 @@ where if let Some(result) = result { if std::intrinsics::unlikely( - tcx.dep_context().sess().opts.debugging_opts.query_dep_graph, + tcx.dep_context().sess().opts.unstable_opts.query_dep_graph, ) { dep_graph.mark_debug_loaded_from_disk(*dep_node) } @@ -486,7 +486,7 @@ where // give us some coverage of potential bugs though. let try_verify = prev_fingerprint.as_value().1 % 32 == 0; if std::intrinsics::unlikely( - try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich, + try_verify || tcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, ) { incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); } @@ -542,8 +542,7 @@ fn incremental_verify_ich<CTX, K, V: Debug>( debug!("BEGIN verify_ich({:?})", dep_node); let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| { - let mut hcx = tcx.create_stable_hashing_context(); - f(&mut hcx, result) + tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result)) }); let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node); debug!("END verify_ich({:?})", dep_node); diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 8bd8eb488b707..5d2b606b43cd5 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -24,4 +24,4 @@ rustc_metadata = { path = "../rustc_metadata" } rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 52706fbb9e6ec..66641fb2cb248 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -259,7 +259,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { fn visit_expr(&mut self, expr: &'a Expr) { let parent_def = match expr.kind { ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), - ExprKind::Closure(_, asyncness, ..) => { + ExprKind::Closure(_, _, asyncness, ..) => { // Async closures desugar to closures inside of closures, so // we must create two defs. let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 86dbcba6c0d51..a820f700869b2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -28,7 +28,7 @@ use rustc_span::{BytePos, Span}; use tracing::debug; use crate::imports::{Import, ImportKind, ImportResolver}; -use crate::late::Rib; +use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize}; use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot}; @@ -508,7 +508,7 @@ impl<'a> Resolver<'a> { E0401, "can't use generic parameters from outer function", ); - err.span_label(span, "use of generic parameter from outer function".to_string()); + err.span_label(span, "use of generic parameter from outer function"); let sm = self.session.source_map(); match outer_res { @@ -896,25 +896,40 @@ impl<'a> Resolver<'a> { err } ResolutionError::BindingShadowsSomethingUnacceptable { - shadowing_binding_descr, + shadowing_binding, name, participle, article, - shadowed_binding_descr, + shadowed_binding, shadowed_binding_span, } => { + let shadowed_binding_descr = shadowed_binding.descr(); let mut err = struct_span_err!( self.session, span, E0530, "{}s cannot shadow {}s", - shadowing_binding_descr, + shadowing_binding.descr(), shadowed_binding_descr, ); err.span_label( span, format!("cannot be named the same as {} {}", article, shadowed_binding_descr), ); + match (shadowing_binding, shadowed_binding) { + ( + PatternSource::Match, + Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _), + ) => { + err.span_suggestion( + span, + "try specify the pattern arguments", + format!("{}(..)", name), + Applicability::Unspecified, + ); + } + _ => (), + } let msg = format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle); err.span_label(shadowed_binding_span, msg); @@ -928,10 +943,7 @@ impl<'a> Resolver<'a> { "generic parameters with a default cannot use \ forward declared identifiers" ); - err.span_label( - span, - "defaulted generic parameters cannot be forward declared".to_string(), - ); + err.span_label(span, "defaulted generic parameters cannot be forward declared"); err } ResolutionError::ParamInTyOfConstParam(name) => { @@ -978,7 +990,7 @@ impl<'a> Resolver<'a> { E0735, "generic parameters cannot use `Self` in their defaults" ); - err.span_label(span, "`Self` in generic parameter default".to_string()); + err.span_label(span, "`Self` in generic parameter default"); err } ResolutionError::UnreachableLabel { name, definition_span, suggestion } => { @@ -1495,6 +1507,21 @@ impl<'a> Resolver<'a> { err.help("have you added the `#[macro_use]` on the module/import?"); return; } + if ident.name == kw::Default + && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind + && let Some(span) = self.opt_span(def_id) + { + let source_map = self.session.source_map(); + let head_span = source_map.guess_head_span(span); + if let Ok(head) = source_map.span_to_snippet(head_span) { + err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect); + } else { + err.span_help( + head_span, + "consider adding `#[derive(Default)]` to this enum", + ); + } + } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( ident, @@ -1620,7 +1647,7 @@ impl<'a> Resolver<'a> { fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { let res = b.res(); - if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() { + if b.span.is_dummy() || !self.session.source_map().is_span_accessible(b.span) { // These already contain the "built-in" prefix or look bad with it. let add_built_in = !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod); @@ -2561,7 +2588,7 @@ fn show_candidates( let span = source_span[local_def_id]; let span = session.source_map().guess_head_span(span); let mut multi_span = MultiSpan::from_span(span); - multi_span.push_span_label(span, "not accessible".to_string()); + multi_span.push_span_label(span, "not accessible"); err.span_note(multi_span, &msg); } else { err.note(&msg); @@ -2580,8 +2607,10 @@ fn show_candidates( } else { "item".to_string() }; + let plural_descr = + if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) }; - let mut msg = format!("{}these {}s exist but are inaccessible", prefix, descr); + let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr); let mut has_colon = false; let mut spans = Vec::new(); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c6aa57f039d4f..e6060ad46650e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1090,31 +1090,31 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut() = Vec::new(); - let mut reexports = Vec::new(); - - module.for_each_child(self.r, |_, ident, _, binding| { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { - let res = binding.res().expect_non_local(); - // Ambiguous imports are treated as errors at this point and are - // not exposed to other crates (see #36837 for more details). - if res != def::Res::Err && !binding.is_ambiguity() { - reexports.push(ModChild { - ident, - res, - vis: binding.vis, - span: binding.span, - macro_rules: false, - }); + if let Some(def_id) = module.opt_def_id() { + let mut reexports = Vec::new(); + + module.for_each_child(self.r, |_, ident, _, binding| { + // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` + // into the crate root to actual `NameBindingKind::Import`. + if binding.is_import() + || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) + { + let res = binding.res().expect_non_local(); + // Ambiguous imports are treated as errors at this point and are + // not exposed to other crates (see #36837 for more details). + if res != def::Res::Err && !binding.is_ambiguity() { + reexports.push(ModChild { + ident, + res, + vis: binding.vis, + span: binding.span, + macro_rules: false, + }); + } } - } - }); + }); - if !reexports.is_empty() { - if let Some(def_id) = module.opt_def_id() { + if !reexports.is_empty() { // Call to `expect_local` should be fine because current // code is only called for local modules. self.r.reexport_map.insert(def_id.expect_local(), reexports); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 640d13ea43547..3ea285b723b0d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -50,7 +50,7 @@ struct BindingInfo { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum PatternSource { +pub enum PatternSource { Match, Let, For, @@ -64,7 +64,7 @@ enum IsRepeatExpr { } impl PatternSource { - fn descr(self) -> &'static str { + pub fn descr(self) -> &'static str { match self { PatternSource::Match => "match binding", PatternSource::Let => "let binding", @@ -268,6 +268,7 @@ enum LifetimeBinderKind { WhereBound, Item, Function, + Closure, ImplBlock, } @@ -281,6 +282,7 @@ impl LifetimeBinderKind { Item => "item", ImplBlock => "impl block", Function => "function", + Closure => "closure", } } } @@ -611,6 +613,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { TyKind::Path(ref qself, ref path) => { self.diagnostic_metadata.current_type_path = Some(ty); self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); + + // Check whether we should interpret this as a bare trait object. + if qself.is_none() + && let Some(partial_res) = self.r.partial_res_map.get(&ty.id) + && partial_res.unresolved_segments() == 0 + && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() + { + // This path is actually a bare trait object. In case of a bare `Fn`-trait + // object with anonymous lifetimes, we need this rib to correctly place the + // synthetic lifetimes. + let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo()); + self.with_generic_param_rib( + &[], + NormalRibKind, + LifetimeRibKind::Generics { + binder: ty.id, + kind: LifetimeBinderKind::PolyTrait, + span, + }, + |this| this.visit_path(&path, ty.id), + ); + self.diagnostic_metadata.current_type_path = prev_ty; + return; + } } TyKind::ImplicitSelf => { let self_ty = Ident::with_dummy_span(kw::SelfUpper); @@ -734,7 +760,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // We don't need to deal with patterns in parameters, because // they are not possible for foreign or bodiless functions. self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, false), + LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: false, + }, |this| walk_list!(this, visit_param, &sig.decl.inputs), ); self.with_lifetime_rib( @@ -768,18 +797,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // generic parameters. This is especially useful for `async fn`, where // these fresh generic parameters can be applied to the opaque `impl Trait` // return type. - let rib = if async_node_id.is_some() { - // Only emit a hard error for `async fn`, since this kind of - // elision has always been allowed in regular `fn`s. + this.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { binder: fn_id, - report_in_path: true, - } - } else { - LifetimeRibKind::AnonymousPassThrough(fn_id, false) - }; - this.with_lifetime_rib( - rib, + // Only emit a hard error for `async fn`, since this kind of + // elision has always been allowed in regular `fn`s. + report_in_path: async_node_id.is_some(), + }, // Add each argument to the rib. |this| this.resolve_params(&declaration.inputs), ); @@ -844,19 +868,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { this.in_func_body = previous_state; } } - FnKind::Closure(declaration, body) => { - // We do not have any explicit generic lifetime parameter. - // FIXME(rfc3216): Change when implementing `for<>` bounds on closures. + FnKind::Closure(binder, declaration, body) => { + this.visit_closure_binder(binder); + this.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - report_in_path: false, + match binder { + // We do not have any explicit generic lifetime parameter. + ClosureBinder::NotPresent => { + LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: false, + } + } + ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError, }, // Add each argument to the rib. |this| this.resolve_params(&declaration.inputs), ); this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, true), + match binder { + ClosureBinder::NotPresent => { + LifetimeRibKind::AnonymousPassThrough(fn_id, true) + } + ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError, + }, |this| visit::walk_fn_ret_ty(this, &declaration.output), ); @@ -891,6 +926,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } + fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) { + match b { + ClosureBinder::NotPresent => {} + ClosureBinder::For { generic_params, .. } => { + self.visit_generic_params( + &generic_params, + self.diagnostic_metadata.current_self_item.is_some(), + ); + } + } + } + fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { debug!("visit_generic_arg({:?})", arg); let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true); @@ -2845,11 +2892,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_error( ident.span, ResolutionError::BindingShadowsSomethingUnacceptable { - shadowing_binding_descr: pat_src.descr(), + shadowing_binding: pat_src, name: ident.name, participle: if binding.is_import() { "imported" } else { "defined" }, article: binding.res().article(), - shadowed_binding_descr: binding.res().descr(), + shadowed_binding: binding.res(), shadowed_binding_span: binding.span, }, ); @@ -2861,11 +2908,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_error( ident.span, ResolutionError::BindingShadowsSomethingUnacceptable { - shadowing_binding_descr: pat_src.descr(), + shadowing_binding: pat_src, name: ident.name, participle: "defined", article: res.article(), - shadowed_binding_descr: res.descr(), + shadowed_binding: res, shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"), } ); @@ -3495,7 +3542,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. - ExprKind::Closure(_, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => { + ExprKind::Closure(_, _, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => { self.with_rib(ValueNS, NormalRibKind, |this| { this.with_label_rib(ClosureOrAsyncRibKind, |this| { // Resolve arguments: @@ -3515,6 +3562,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } // For closures, ClosureOrAsyncRibKind is added in visit_fn + ExprKind::Closure(ClosureBinder::For { ref generic_params, span }, ..) => { + self.with_generic_param_rib( + &generic_params, + NormalRibKind, + LifetimeRibKind::Generics { + binder: expr.id, + kind: LifetimeBinderKind::Closure, + span, + }, + |this| visit::walk_expr(this, expr), + ); + } ExprKind::Closure(..) => visit::walk_expr(self, expr), ExprKind::Async(..) => { self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr)); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 68bcba7147bba..1e53c73620a08 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -70,6 +70,8 @@ pub(crate) enum ForLifetimeSpanType { BoundTail, TypeEmpty, TypeTail, + ClosureEmpty, + ClosureTail, } impl ForLifetimeSpanType { @@ -77,13 +79,15 @@ impl ForLifetimeSpanType { match self { Self::BoundEmpty | Self::BoundTail => "bound", Self::TypeEmpty | Self::TypeTail => "type", + Self::ClosureEmpty | Self::ClosureTail => "closure", } } pub(crate) fn suggestion(&self, sugg: &str) -> String { match self { Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), - Self::BoundTail | Self::TypeTail => format!(", {}", sugg), + Self::ClosureEmpty => format!("for<{}>", sugg), + Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg), } } } @@ -349,10 +353,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.code(rustc_errors::error_code!(E0424)); err.span_label(span, match source { - PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed" - .to_string(), - _ => "`self` value is a keyword only available in methods with a `self` parameter" - .to_string(), + PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed", + _ => "`self` value is a keyword only available in methods with a `self` parameter", }); if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function { // The current function has a `self' parameter, but we were unable to resolve @@ -601,10 +603,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { }; multi_span.push_span_label(sp, msg); } - multi_span.push_span_label( - base_error.span, - "expected this type to be a trait...".to_string(), - ); + multi_span + .push_span_label(base_error.span, "expected this type to be a trait..."); err.span_help( multi_span, "`+` is used to constrain a \"trait object\" type with lifetimes or \ @@ -1227,17 +1227,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let mut m: MultiSpan = non_visible_spans.clone().into(); non_visible_spans .into_iter() - .for_each(|s| m.push_span_label(s, "private field".to_string())); + .for_each(|s| m.push_span_label(s, "private field")); err.span_note(m, "constructor is not visible here due to private fields"); } return true; } - err.span_label( - span, - "constructor is not visible here due to private fields".to_string(), - ); + err.span_label(span, "constructor is not visible here due to private fields"); } ( Res::Def( @@ -1508,6 +1505,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { Some(match name { "byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes. "short" => sym::i16, + "Bool" => sym::bool, + "Boolean" => sym::bool, "boolean" => sym::bool, "int" => sym::i32, "long" => sym::i64, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index ed5d1165c7d0d..0eb11cd3e9fad 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node}; -use rustc_hir::{GenericParamKind, HirIdMap}; +use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; @@ -571,7 +571,54 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind { + if let hir::ExprKind::Closure(hir::Closure { + binder, bound_generic_params, fn_decl, .. + }) = e.kind + { + if let &hir::ClosureBinder::For { span: for_sp, .. } = binder { + fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> { + struct V(Option<Span>); + + impl<'v> Visitor<'v> for V { + fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { + match t.kind { + _ if self.0.is_some() => (), + hir::TyKind::Infer => { + self.0 = Some(t.span); + } + _ => intravisit::walk_ty(self, t), + } + } + } + + let mut v = V(None); + v.visit_ty(ty); + v.0 + } + + let infer_in_rt_sp = match fn_decl.output { + hir::FnRetTy::DefaultReturn(sp) => Some(sp), + hir::FnRetTy::Return(ty) => span_of_infer(ty), + }; + + let infer_spans = fn_decl + .inputs + .into_iter() + .filter_map(span_of_infer) + .chain(infer_in_rt_sp) + .collect::<Vec<_>>(); + + if !infer_spans.is_empty() { + self.tcx.sess + .struct_span_err( + infer_spans, + "implicit types in closure signatures are forbidden when `for<...>` is present", + ) + .span_label(for_sp, "`for<...>` is here") + .emit(); + } + } + let next_early_index = self.next_early_index(); let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = bound_generic_params @@ -584,6 +631,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { (pair, r) }) .unzip(); + self.map.late_bound_vars.insert(e.hir_id, binders); let scope = Scope::Binder { hir_id: e.hir_id, @@ -595,11 +643,41 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { allow_late_bound: true, where_bound_origin: None, }; + + if let &hir::ClosureBinder::For { span, .. } = binder { + let last_lt = bound_generic_params + .iter() + .filter(|p| { + matches!( + p, + GenericParam { + kind: GenericParamKind::Lifetime { + kind: LifetimeParamKind::Explicit + }, + .. + } + ) + }) + .last(); + let (span, span_type) = match last_lt { + Some(GenericParam { span: last_sp, .. }) => { + (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail) + } + None => (span, ForLifetimeSpanType::ClosureEmpty), + }; + self.missing_named_lifetime_spots + .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + } + self.with(scope, |this| { // a closure has no bounds, so everything // contained within is scoped within its binder. intravisit::walk_expr(this, e) }); + + if let hir::ClosureBinder::For { .. } = binder { + self.missing_named_lifetime_spots.pop(); + } } else { intravisit::walk_expr(self, e) } @@ -1677,7 +1755,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break None; } - Scope::Binder { ref lifetimes, scope_type, s, .. } => { + Scope::Binder { ref lifetimes, scope_type, s, where_bound_origin, .. } => { if let Some(&def) = lifetimes.get(®ion_def_id) { break Some(def.shifted(late_depth)); } @@ -1685,6 +1763,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { BinderScopeType::Normal => late_depth += 1, BinderScopeType::Concatenating => {} } + // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in + // regular fns. + if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin + && let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name + && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner) + && !self.tcx.features().anonymous_lifetime_in_impl_trait + { + rustc_session::parse::feature_err( + &self.tcx.sess.parse_sess, + sym::anonymous_lifetime_in_impl_trait, + lifetime_ref.span, + "anonymous lifetimes in `impl Trait` are unstable", + ).emit(); + return; + } scope = s; } @@ -2539,12 +2632,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// "Constrained" basically means that it appears in any type but /// not amongst the inputs to a projection. In other words, `<&'a /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. -fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> { +fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?; let generics = tcx.hir().get_generics(def_id)?; - let mut late_bound = FxHashSet::default(); + let mut late_bound = FxIndexSet::default(); let mut constrained_by_input = ConstrainedCollector::default(); for arg_ty in decl.inputs { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 57384877da550..2fcbe1d4c14a5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,10 +10,9 @@ #![feature(box_patterns)] #![feature(drain_filter)] #![feature(if_let_guard)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(never_type)] -#![cfg_attr(bootstrap, feature(nll))] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] #![allow(rustc::potential_query_instability)] @@ -62,7 +61,7 @@ use tracing::debug; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; -use late::{HasGenericParams, PathSource}; +use late::{HasGenericParams, PathSource, PatternSource}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::access_levels::AccessLevelsVisitor; @@ -231,11 +230,11 @@ enum ResolutionError<'a> { ), /// Error E0530: `X` bindings cannot shadow `Y`s. BindingShadowsSomethingUnacceptable { - shadowing_binding_descr: &'static str, + shadowing_binding: PatternSource, name: Symbol, participle: &'static str, article: &'static str, - shadowed_binding_descr: &'static str, + shadowed_binding: Res, shadowed_binding_span: Span, }, /// Error E0128: generic parameters with a default cannot use forward-declared identifiers. diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 6eb2f2d929d57..e2e0e1f5b300a 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -82,14 +82,7 @@ impl<'tcx> DumpVisitor<'tcx> { pub fn new(save_ctxt: SaveContext<'tcx>) -> DumpVisitor<'tcx> { let span_utils = SpanUtils::new(&save_ctxt.tcx.sess); let dumper = Dumper::new(save_ctxt.config.clone()); - DumpVisitor { - tcx: save_ctxt.tcx, - save_ctxt, - dumper, - span: span_utils, - // mac_defs: FxHashSet::default(), - // macro_calls: FxHashSet::default(), - } + DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils } } pub fn analysis(&self) -> &rls_data::Analysis { @@ -1360,7 +1353,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } } } - hir::ExprKind::Closure { ref fn_decl, body, .. } => { + hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => { let id = format!("${}", ex.hir_id); // walk arg and return types @@ -1425,9 +1418,10 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { self.process_macro_use(l.span); self.process_var_decl(&l.pat); - // Just walk the initializer and type (don't want to walk the pattern again). + // Just walk the initializer, the else branch and type (don't want to walk the pattern again). walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); + walk_list!(self, visit_block, l.els); } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 99f38b3222dca..0a0c674d179e9 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -623,9 +623,9 @@ impl<'tcx> SaveContext<'tcx> { } }, - Node::Binding(&hir::Pat { - kind: hir::PatKind::Binding(_, canonical_id, ..), .. - }) => Res::Local(canonical_id), + Node::Pat(&hir::Pat { kind: hir::PatKind::Binding(_, canonical_id, ..), .. }) => { + Res::Local(canonical_id) + } _ => Res::Err, } diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index f6b9e17e58ed9..5056163b7fe7d 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] indexmap = "1.8.0" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } [dev-dependencies] rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 366efe9cfa519..5c17ef6ace2d5 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -297,6 +297,10 @@ impl FileEncoder { } } + pub fn file(&self) -> &File { + &self.file + } + #[inline] fn capacity(&self) -> usize { self.buf.len() diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index cbb03ffd7a083..eede4d16ea378 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -1,11 +1,12 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lock; +use rustc_span::Symbol; use rustc_target::abi::{Align, Size}; use std::cmp::{self, Ordering}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct VariantInfo { - pub name: Option<String>, + pub name: Option<Symbol>, pub kind: SizeKind, pub size: u64, pub align: u64, @@ -20,7 +21,7 @@ pub enum SizeKind { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct FieldInfo { - pub name: String, + pub name: Symbol, pub offset: u64, pub size: u64, pub align: u64, @@ -119,7 +120,7 @@ impl CodeStats { let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info; let indent = if !struct_like { let name = match name.as_ref() { - Some(name) => name.to_owned(), + Some(name) => name.to_string(), None => i.to_string(), }; println!( diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 14ad1a42a7d83..0e52bf34661d6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -722,10 +722,11 @@ impl Default for Options { target_triple: TargetTriple::from_triple(host_triple()), test: false, incremental: None, - debugging_opts: Default::default(), + unstable_opts: Default::default(), prints: Vec::new(), cg: Default::default(), error_format: ErrorOutputType::default(), + diagnostic_width: None, externs: Externs(BTreeMap::new()), crate_name: None, libs: Vec::new(), @@ -751,8 +752,8 @@ impl Options { /// Returns `true` if there is a reason to build the dep graph. pub fn build_dep_graph(&self) -> bool { self.incremental.is_some() - || self.debugging_opts.dump_dep_graph - || self.debugging_opts.query_dep_graph + || self.unstable_opts.dump_dep_graph + || self.unstable_opts.query_dep_graph } pub fn file_path_mapping(&self) -> FilePathMapping { @@ -761,13 +762,13 @@ impl Options { /// Returns `true` if there will be an output file generated. pub fn will_create_output_file(&self) -> bool { - !self.debugging_opts.parse_only && // The file is just being parsed - !self.debugging_opts.ls // The file is just being queried + !self.unstable_opts.parse_only && // The file is just being parsed + !self.unstable_opts.ls // The file is just being queried } #[inline] pub fn share_generics(&self) -> bool { - match self.debugging_opts.share_generics { + match self.unstable_opts.share_generics { Some(setting) => setting, None => match self.optimize { OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true, @@ -781,7 +782,7 @@ impl Options { } } -impl DebuggingOptions { +impl UnstableOptions { pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags { HandlerFlags { can_emit_warnings, @@ -939,7 +940,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let panic_strategy = sess.panic_strategy(); ret.insert((sym::panic, Some(panic_strategy.desc_symbol()))); - for s in sess.opts.debugging_opts.sanitizer { + for s in sess.opts.unstable_opts.sanitizer { let symbol = Symbol::intern(&s.to_string()); ret.insert((sym::sanitize, Some(symbol))); } @@ -1102,49 +1103,6 @@ impl CrateCheckConfig { .extend(atomic_values); // Target specific values - #[cfg(bootstrap)] - { - for target in TARGETS - .iter() - .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) - { - self.values_valid - .entry(sym::target_os) - .or_default() - .insert(Symbol::intern(&target.options.os)); - self.values_valid - .entry(sym::target_family) - .or_default() - .extend(target.options.families.iter().map(|family| Symbol::intern(family))); - self.values_valid - .entry(sym::target_arch) - .or_default() - .insert(Symbol::intern(&target.arch)); - self.values_valid - .entry(sym::target_endian) - .or_default() - .insert(Symbol::intern(&target.options.endian.as_str())); - self.values_valid - .entry(sym::target_env) - .or_default() - .insert(Symbol::intern(&target.options.env)); - self.values_valid - .entry(sym::target_abi) - .or_default() - .insert(Symbol::intern(&target.options.abi)); - self.values_valid - .entry(sym::target_vendor) - .or_default() - .insert(Symbol::intern(&target.options.vendor)); - self.values_valid - .entry(sym::target_pointer_width) - .or_default() - .insert(sym::integer(target.pointer_width)); - } - } - - // Target specific values - #[cfg(not(bootstrap))] { const VALUES: [&Symbol; 8] = [ &sym::target_os, @@ -1445,6 +1403,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { /// long-term interface for rustc. pub fn rustc_optgroups() -> Vec<RustcOptGroup> { let mut opts = rustc_short_optgroups(); + // FIXME: none of these descriptions are actually used opts.extend(vec![ opt::multi_s( "", @@ -1453,7 +1412,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> { "NAME[=PATH]", ), opt::opt_s("", "sysroot", "Override the system root", "PATH"), - opt::multi("Z", "", "Set internal debugging options", "FLAG"), + opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"), opt::opt_s( "", "error-format", @@ -1470,6 +1429,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> { never = never colorize output", "auto|always|never", ), + opt::opt_s( + "", + "diagnostic-width", + "Inform rustc of the width of the output so that diagnostics can be truncated to fit", + "WIDTH", + ), opt::multi_s( "", "remap-path-prefix", @@ -1695,12 +1660,12 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { edition } -fn check_debug_option_stability( - debugging_opts: &DebuggingOptions, +fn check_error_format_stability( + unstable_opts: &UnstableOptions, error_format: ErrorOutputType, json_rendered: HumanReadableErrorType, ) { - if !debugging_opts.unstable_options { + if !unstable_opts.unstable_options { if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { early_error( ErrorOutputType::Json { pretty: false, json_rendered }, @@ -1719,12 +1684,12 @@ fn check_debug_option_stability( } fn parse_output_types( - debugging_opts: &DebuggingOptions, + unstable_opts: &UnstableOptions, matches: &getopts::Matches, error_format: ErrorOutputType, ) -> OutputTypes { let mut output_types = BTreeMap::new(); - if !debugging_opts.parse_only { + if !unstable_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { let (shorthand, path) = match output_type.split_once('=') { @@ -1798,19 +1763,19 @@ fn should_override_cgus_and_disable_thinlto( (disable_thinlto, codegen_units) } -fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) { - if debugging_opts.threads == 0 { +fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) { + if unstable_opts.threads == 0 { early_error(error_format, "value for threads must be a positive non-zero integer"); } - if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() { + if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() { early_error(error_format, "optimization fuel is incompatible with multiple threads"); } } fn collect_print_requests( cg: &mut CodegenOptions, - dopts: &mut DebuggingOptions, + unstable_opts: &mut UnstableOptions, matches: &getopts::Matches, error_format: ErrorOutputType, ) -> Vec<PrintRequest> { @@ -1839,7 +1804,7 @@ fn collect_print_requests( "native-static-libs" => PrintRequest::NativeStaticLibs, "stack-protector-strategies" => PrintRequest::StackProtectorStrategies, "target-spec-json" => { - if dopts.unstable_options { + if unstable_opts.unstable_options { PrintRequest::TargetSpec } else { early_error( @@ -2105,10 +2070,10 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec< pub fn parse_externs( matches: &getopts::Matches, - debugging_opts: &DebuggingOptions, + unstable_opts: &UnstableOptions, error_format: ErrorOutputType, ) -> Externs { - let is_unstable_enabled = debugging_opts.unstable_options; + let is_unstable_enabled = unstable_opts.unstable_options; let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new(); for arg in matches.opt_strs("extern") { let (name, path) = match arg.split_once('=') { @@ -2207,7 +2172,7 @@ pub fn parse_externs( fn parse_remap_path_prefix( matches: &getopts::Matches, - debugging_opts: &DebuggingOptions, + unstable_opts: &UnstableOptions, error_format: ErrorOutputType, ) -> Vec<(PathBuf, PathBuf)> { let mut mapping: Vec<(PathBuf, PathBuf)> = matches @@ -2221,7 +2186,7 @@ fn parse_remap_path_prefix( Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) .collect(); - match &debugging_opts.remap_cwd_prefix { + match &unstable_opts.remap_cwd_prefix { Some(to) => match std::env::current_dir() { Ok(cwd) => mapping.push((cwd, to.clone())), Err(_) => (), @@ -2245,16 +2210,20 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let error_format = parse_error_format(matches, color, json_rendered); + let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| { + early_error(error_format, "`--diagnostic-width` must be an positive integer"); + }); + let unparsed_crate_types = matches.opt_strs("crate-type"); let crate_types = parse_crate_types_from_list(unparsed_crate_types) .unwrap_or_else(|e| early_error(error_format, &e)); - let mut debugging_opts = DebuggingOptions::build(matches, error_format); + let mut unstable_opts = UnstableOptions::build(matches, error_format); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); - check_debug_option_stability(&debugging_opts, error_format, json_rendered); + check_error_format_stability(&unstable_opts, error_format, json_rendered); - if !debugging_opts.unstable_options && json_unused_externs.is_enabled() { + if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { early_error( error_format, "the `-Z unstable-options` flag must also be passed to enable \ @@ -2262,7 +2231,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - let output_types = parse_output_types(&debugging_opts, matches, error_format); + let output_types = parse_output_types(&unstable_opts, matches, error_format); let mut cg = CodegenOptions::build(matches, error_format); let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto( @@ -2272,20 +2241,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { cg.codegen_units, ); - check_thread_count(&debugging_opts, error_format); + check_thread_count(&unstable_opts, error_format); let incremental = cg.incremental.as_ref().map(PathBuf::from); - let assert_incr_state = - parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format); + let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format); - if debugging_opts.profile && incremental.is_some() { + if unstable_opts.profile && incremental.is_some() { early_error( error_format, "can't instrument with gcov profiling when compiling incrementally", ); } - if debugging_opts.profile { + if unstable_opts.profile { match codegen_units { Some(1) => {} None => codegen_units = Some(1), @@ -2303,7 +2271,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - if debugging_opts.profile_sample_use.is_some() + if unstable_opts.profile_sample_use.is_some() && (cg.profile_generate.enabled() || cg.profile_use.is_some()) { early_error( @@ -2314,7 +2282,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes // precedence. - match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) { + match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) { (Some(smv_c), Some(smv_z)) if smv_c != smv_z => { early_error( error_format, @@ -2323,7 +2291,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } (Some(SymbolManglingVersion::V0), _) => {} - (Some(_), _) if !debugging_opts.unstable_options => { + (Some(_), _) if !unstable_opts.unstable_options => { early_error( error_format, "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", @@ -2342,7 +2310,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes // precedence. - match (cg.instrument_coverage, debugging_opts.instrument_coverage) { + match (cg.instrument_coverage, unstable_opts.instrument_coverage) { (Some(ic_c), Some(ic_z)) if ic_c != ic_z => { early_error( error_format, @@ -2351,7 +2319,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {} - (Some(_), _) if !debugging_opts.unstable_options => { + (Some(_), _) if !unstable_opts.unstable_options => { early_error( error_format, "`-C instrument-coverage=except-*` requires `-Z unstable-options`", @@ -2395,7 +2363,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { - debugging_opts.graphviz_font = graphviz_font; + unstable_opts.graphviz_font = graphviz_font; } if !cg.embed_bitcode { @@ -2418,7 +2386,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format); + let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format); let cg = cg; @@ -2444,15 +2412,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations"); } - let externs = parse_externs(matches, &debugging_opts, error_format); + let externs = parse_externs(matches, &unstable_opts, error_format); let crate_name = matches.opt_str("crate-name"); - let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format); + let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format); - let pretty = parse_pretty(&debugging_opts, error_format); + let pretty = parse_pretty(&unstable_opts, error_format); - if !debugging_opts.unstable_options + if !unstable_opts.unstable_options && !target_triple.triple().contains("apple") && cg.split_debuginfo.is_some() { @@ -2513,10 +2481,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { target_triple, test, incremental, - debugging_opts, + unstable_opts, prints, cg, error_format, + diagnostic_width, externs, unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), crate_name, @@ -2537,10 +2506,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } -fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> { +fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> { use PpMode::*; - let first = match debugging_opts.unpretty.as_deref()? { + let first = match unstable_opts.unpretty.as_deref()? { "normal" => Source(PpSourceMode::Normal), "identified" => Source(PpSourceMode::Identified), "expanded" => Source(PpSourceMode::Expanded), @@ -2767,8 +2736,8 @@ pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel, - OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, - SymbolManglingVersion, TrimmedDefPaths, + OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind, + SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -2855,6 +2824,7 @@ pub(crate) mod dep_tracking { Edition, LinkerPluginLto, SplitDebuginfo, + SplitDwarfKind, StackProtector, SwitchWithOptPath, SymbolManglingVersion, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 35b55981e37ea..44cf504864254 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,12 +1,12 @@ #![feature(if_let_guard)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(min_specialization)] #![feature(never_type)] #![feature(once_cell)] #![feature(option_get_or_insert_default)] #![feature(rustc_attrs)] -#![cfg_attr(not(bootstrap), feature(map_many_mut))] +#![feature(map_many_mut)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 441e1f9f6a2b8..01ff9e254f792 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -104,7 +104,7 @@ macro_rules! top_level_options { impl Options { pub fn mir_opt_level(&self) -> usize { - self.debugging_opts + self.unstable_opts .mir_opt_level .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 }) } @@ -170,13 +170,14 @@ top_level_options!( test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], + diagnostic_width: Option<usize> [UNTRACKED], /// If `Some`, enable incremental compilation, using the given /// directory to store intermediate results. incremental: Option<PathBuf> [UNTRACKED], assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED], - debugging_opts: DebuggingOptions [SUBSTRUCT], + unstable_opts: UnstableOptions [SUBSTRUCT], prints: Vec<PrintRequest> [UNTRACKED], cg: CodegenOptions [SUBSTRUCT], externs: Externs [UNTRACKED], @@ -1186,12 +1187,13 @@ options! { } options! { - DebuggingOptions, DB_OPTIONS, dbopts, "Z", "debugging", + UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable", // This list is in alphabetical order. // // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs + // - src/doc/unstable-book/src/compiler-flags allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED], "only allow the listed language features to be enabled in code (space separated)"), @@ -1245,6 +1247,8 @@ options! { dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \ (default: no)"), + dump_drop_tracking_cfg: Option<String> = (None, parse_opt_string, [UNTRACKED], + "dump drop-tracking control-flow graph as a `.dot` file (default: no)"), dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED], "dump MIR state to file. `val` is used to select which passes and functions to dump. For example: @@ -1269,6 +1273,8 @@ options! { computed `block` spans (one span encompassing a block's terminator and \ all statements). If `-Z instrument-coverage` is also enabled, create \ an additional `.html` file showing the computed coverage spans."), + dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], + "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], @@ -1388,6 +1394,8 @@ options! { "panic strategy for out-of-memory handling"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the macOS linker (default: no)"), + diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED], + "set the current output width for diagnostic truncation"), panic_abort_tests: bool = (false, parse_bool, [TRACKED], "support compiling tests with panic=abort (default: no)"), panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED], @@ -1496,7 +1504,7 @@ options! { "control if mem::uninitialized and mem::zeroed panic on more UB"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), - split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED], + split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED], "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) (default: `split`) @@ -1504,7 +1512,7 @@ options! { file which is ignored by the linker `single`: sections which do not require relocation are written into object file but ignored by the linker"), - split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED], + split_dwarf_inlining: bool = (true, parse_bool, [TRACKED], "provide minimal debug info in the object/executable to facilitate online \ symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), symbol_mangling_version: Option<SymbolManglingVersion> = (None, @@ -1514,8 +1522,6 @@ options! { "show extended diagnostic help (default: no)"), temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED], "the directory the intermediate files are written to"), - terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED], - "set the current terminal width"), // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved // alongside query results and changes to translation options can affect diagnostics - so // translation options should be tracked. @@ -1575,6 +1581,8 @@ options! { `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), unsound_mir_opts: bool = (false, parse_bool, [TRACKED], "enable unsound and buggy MIR optimizations (default: no)"), + /// This name is kind of confusing: Most unstable options enable something themselves, while + /// this just allows "normal" options to be feature-gated. unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index a5ccae047fcc3..f31d52147b47b 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -311,7 +311,7 @@ impl ParseSess { self.create_warning(warning).emit() } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_err( &self, msg: impl Into<DiagnosticMessage>, @@ -319,7 +319,7 @@ impl ParseSess { self.span_diagnostic.struct_err(msg) } - #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] + #[rustc_lint_diagnostics] pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { self.span_diagnostic.struct_warn(msg) } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f1814eebfa6fd..854cad79a2040 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -2,7 +2,7 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, OutputType, SwitchWithOptPath}; -use crate::parse::ParseSess; +use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; @@ -194,6 +194,9 @@ pub struct Session { /// Set of enabled features for the current target. pub target_features: FxHashSet<Symbol>, + + /// Set of enabled features for the current target, including unstable ones. + pub unstable_target_features: FxHashSet<Symbol>, } pub struct PerfStats { @@ -280,6 +283,7 @@ impl Session { self.crate_types.set(crate_types).expect("`crate_types` was initialized twice") } + #[rustc_lint_diagnostics] pub fn struct_span_warn<S: Into<MultiSpan>>( &self, sp: S, @@ -287,6 +291,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_warn(sp, msg) } + #[rustc_lint_diagnostics] pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>( &self, sp: S, @@ -295,6 +300,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } + #[rustc_lint_diagnostics] pub fn struct_span_warn_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -303,9 +309,11 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } + #[rustc_lint_diagnostics] pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } + #[rustc_lint_diagnostics] pub fn struct_warn_with_expectation( &self, msg: impl Into<DiagnosticMessage>, @@ -313,6 +321,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn_with_expectation(msg, id) } + #[rustc_lint_diagnostics] pub fn struct_span_allow<S: Into<MultiSpan>>( &self, sp: S, @@ -320,9 +329,11 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_allow(sp, msg) } + #[rustc_lint_diagnostics] pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } + #[rustc_lint_diagnostics] pub fn struct_expect( &self, msg: impl Into<DiagnosticMessage>, @@ -330,6 +341,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_expect(msg, id) } + #[rustc_lint_diagnostics] pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -337,6 +349,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { self.diagnostic().struct_span_err(sp, msg) } + #[rustc_lint_diagnostics] pub fn struct_span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -346,12 +359,14 @@ impl Session { self.diagnostic().struct_span_err_with_code(sp, msg, code) } // FIXME: This method should be removed (every error should have an associated error code). + #[rustc_lint_diagnostics] pub fn struct_err( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { self.parse_sess.struct_err(msg) } + #[rustc_lint_diagnostics] pub fn struct_err_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -359,6 +374,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { self.diagnostic().struct_err_with_code(msg, code) } + #[rustc_lint_diagnostics] pub fn struct_warn_with_code( &self, msg: impl Into<DiagnosticMessage>, @@ -366,6 +382,7 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn_with_code(msg, code) } + #[rustc_lint_diagnostics] pub fn struct_span_fatal<S: Into<MultiSpan>>( &self, sp: S, @@ -373,6 +390,7 @@ impl Session { ) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_span_fatal(sp, msg) } + #[rustc_lint_diagnostics] pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -381,13 +399,16 @@ impl Session { ) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } + #[rustc_lint_diagnostics] pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_fatal(msg) } + #[rustc_lint_diagnostics] pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! { self.diagnostic().span_fatal(sp, msg) } + #[rustc_lint_diagnostics] pub fn span_fatal_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -396,9 +417,11 @@ impl Session { ) -> ! { self.diagnostic().span_fatal_with_code(sp, msg, code) } + #[rustc_lint_diagnostics] pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! { self.diagnostic().fatal(msg).raise() } + #[rustc_lint_diagnostics] pub fn span_err_or_warn<S: Into<MultiSpan>>( &self, is_warning: bool, @@ -411,6 +434,7 @@ impl Session { self.span_err(sp, msg); } } + #[rustc_lint_diagnostics] pub fn span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -418,6 +442,7 @@ impl Session { ) -> ErrorGuaranteed { self.diagnostic().span_err(sp, msg) } + #[rustc_lint_diagnostics] pub fn span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -426,6 +451,7 @@ impl Session { ) { self.diagnostic().span_err_with_code(sp, msg, code) } + #[rustc_lint_diagnostics] pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { self.diagnostic().err(msg) } @@ -435,6 +461,15 @@ impl Session { ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { self.parse_sess.create_err(err) } + pub fn create_feature_err<'a>( + &'a self, + err: impl SessionDiagnostic<'a>, + feature: Symbol, + ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut err = self.parse_sess.create_err(err); + add_feature_diagnostics(&mut err, &self.parse_sess, feature); + err + } pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { self.parse_sess.emit_err(err) } @@ -509,10 +544,10 @@ impl Session { /// warnings or errors are emitted. If no messages are emitted ("good path"), then /// it's likely a bug. pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) { - if self.opts.debugging_opts.print_type_sizes - || self.opts.debugging_opts.query_dep_graph - || self.opts.debugging_opts.dump_mir.is_some() - || self.opts.debugging_opts.unpretty.is_some() + if self.opts.unstable_opts.print_type_sizes + || self.opts.unstable_opts.query_dep_graph + || self.opts.unstable_opts.dump_mir.is_some() + || self.opts.unstable_opts.unpretty.is_some() || self.opts.output_types.contains_key(&OutputType::Mir) || std::env::var_os("RUSTC_LOG").is_some() { @@ -549,31 +584,31 @@ impl Session { self.parse_sess.source_map() } pub fn verbose(&self) -> bool { - self.opts.debugging_opts.verbose + self.opts.unstable_opts.verbose } pub fn time_passes(&self) -> bool { - self.opts.debugging_opts.time_passes || self.opts.debugging_opts.time + self.opts.unstable_opts.time_passes || self.opts.unstable_opts.time } pub fn instrument_mcount(&self) -> bool { - self.opts.debugging_opts.instrument_mcount + self.opts.unstable_opts.instrument_mcount } pub fn time_llvm_passes(&self) -> bool { - self.opts.debugging_opts.time_llvm_passes + self.opts.unstable_opts.time_llvm_passes } pub fn meta_stats(&self) -> bool { - self.opts.debugging_opts.meta_stats + self.opts.unstable_opts.meta_stats } pub fn asm_comments(&self) -> bool { - self.opts.debugging_opts.asm_comments + self.opts.unstable_opts.asm_comments } pub fn verify_llvm_ir(&self) -> bool { - self.opts.debugging_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some() + self.opts.unstable_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some() } pub fn print_llvm_passes(&self) -> bool { - self.opts.debugging_opts.print_llvm_passes + self.opts.unstable_opts.print_llvm_passes } pub fn binary_dep_depinfo(&self) -> bool { - self.opts.debugging_opts.binary_dep_depinfo + self.opts.unstable_opts.binary_dep_depinfo } pub fn mir_opt_level(&self) -> usize { self.opts.mir_opt_level() @@ -640,7 +675,7 @@ impl Session { // If `-Z thinlto` specified process that, but note that this is mostly // a deprecated option now that `-C lto=thin` exists. - if let Some(enabled) = self.opts.debugging_opts.thinlto { + if let Some(enabled) = self.opts.unstable_opts.thinlto { if enabled { return config::Lto::ThinLocal; } else { @@ -668,25 +703,25 @@ impl Session { self.opts.cg.panic.unwrap_or(self.target.panic_strategy) } pub fn fewer_names(&self) -> bool { - if let Some(fewer_names) = self.opts.debugging_opts.fewer_names { + if let Some(fewer_names) = self.opts.unstable_opts.fewer_names { fewer_names } else { let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) || self.opts.output_types.contains_key(&OutputType::Bitcode) // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. - || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); + || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); !more_names } } pub fn unstable_options(&self) -> bool { - self.opts.debugging_opts.unstable_options + self.opts.unstable_opts.unstable_options } pub fn is_nightly_build(&self) -> bool { self.opts.unstable_features.is_nightly_build() } pub fn is_sanitizer_cfi_enabled(&self) -> bool { - self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI) + self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) } pub fn overflow_checks(&self) -> bool { self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions) @@ -726,13 +761,13 @@ impl Session { } pub fn tls_model(&self) -> TlsModel { - self.opts.debugging_opts.tls_model.unwrap_or(self.target.tls_model) + self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model) } pub fn is_wasi_reactor(&self) -> bool { self.target.options.os == "wasi" && matches!( - self.opts.debugging_opts.wasi_exec_model, + self.opts.unstable_opts.wasi_exec_model, Some(config::WasiExecModel::Reactor) ) } @@ -743,7 +778,7 @@ impl Session { pub fn stack_protector(&self) -> StackProtector { if self.target.options.supports_stack_protector { - self.opts.debugging_opts.stack_protector + self.opts.unstable_opts.stack_protector } else { StackProtector::None } @@ -898,7 +933,7 @@ impl Session { /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; - if let Some((ref c, _)) = self.opts.debugging_opts.fuel { + if let Some((ref c, _)) = self.opts.unstable_opts.fuel { if c == crate_name { assert_eq!(self.threads(), 1); let mut fuel = self.optimization_fuel.lock(); @@ -916,7 +951,7 @@ impl Session { } } } - if let Some(ref c) = self.opts.debugging_opts.print_fuel { + if let Some(ref c) = self.opts.unstable_opts.print_fuel { if c == crate_name { assert_eq!(self.threads(), 1); self.print_fuel.fetch_add(1, SeqCst); @@ -928,7 +963,7 @@ impl Session { /// Returns the number of query threads that should be used for this /// compilation pub fn threads(&self) -> usize { - self.opts.debugging_opts.threads + self.opts.unstable_opts.threads } /// Returns the number of codegen units that should be used for this @@ -1002,7 +1037,7 @@ impl Session { } pub fn teach(&self, code: &DiagnosticId) -> bool { - self.opts.debugging_opts.teach && self.diagnostic().must_teach(code) + self.opts.unstable_opts.teach && self.diagnostic().must_teach(code) } pub fn rust_2015(&self) -> bool { @@ -1034,7 +1069,7 @@ impl Session { // The user can use the command line flag to override it. let needs_plt = self.target.needs_plt; - let dbg_opts = &self.opts.debugging_opts; + let dbg_opts = &self.opts.unstable_opts; let relro_level = dbg_opts.relro_level.unwrap_or(self.target.relro_level); @@ -1054,7 +1089,7 @@ impl Session { // AddressSanitizer uses lifetimes to detect use after scope bugs. // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future. - || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) + || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) } pub fn link_dead_code(&self) -> bool { @@ -1116,7 +1151,7 @@ fn default_emitter( fallback_bundle: LazyFallbackBundle, emitter_dest: Option<Box<dyn Write + Send>>, ) -> Box<dyn Emitter + sync::Send> { - let macro_backtrace = sopts.debugging_opts.macro_backtrace; + let macro_backtrace = sopts.unstable_opts.macro_backtrace; match (sopts.error_format, emitter_dest) { (config::ErrorOutputType::HumanReadable(kind), dst) => { let (short, color_config) = kind.unzip(); @@ -1129,7 +1164,7 @@ fn default_emitter( short, macro_backtrace, ); - Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) + Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { let emitter = match dst { None => EmitterWriter::stderr( @@ -1138,8 +1173,8 @@ fn default_emitter( bundle, fallback_bundle, short, - sopts.debugging_opts.teach, - sopts.debugging_opts.terminal_width, + sopts.unstable_opts.teach, + sopts.diagnostic_width, macro_backtrace, ), Some(dst) => EmitterWriter::new( @@ -1150,11 +1185,11 @@ fn default_emitter( short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer - None, // no terminal width + None, // no diagnostic width macro_backtrace, ), }; - Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) + Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } } (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new( @@ -1165,10 +1200,10 @@ fn default_emitter( fallback_bundle, pretty, json_rendered, - sopts.debugging_opts.terminal_width, + sopts.diagnostic_width, macro_backtrace, ) - .ui_testing(sopts.debugging_opts.ui_testing), + .ui_testing(sopts.unstable_opts.ui_testing), ), (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( JsonEmitter::new( @@ -1179,10 +1214,10 @@ fn default_emitter( fallback_bundle, pretty, json_rendered, - sopts.debugging_opts.terminal_width, + sopts.diagnostic_width, macro_backtrace, ) - .ui_testing(sopts.debugging_opts.ui_testing), + .ui_testing(sopts.unstable_opts.ui_testing), ), } } @@ -1235,7 +1270,7 @@ pub fn build_session( } let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); - let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| { + let hash_kind = sopts.unstable_opts.src_hash_algorithm.unwrap_or_else(|| { if target_cfg.is_like_msvc { SourceFileHashAlgorithm::Sha1 } else { @@ -1250,17 +1285,17 @@ pub fn build_session( let fallback_bundle = fallback_fluent_bundle( rustc_errors::DEFAULT_LOCALE_RESOURCES, - sopts.debugging_opts.translate_directionality_markers, + sopts.unstable_opts.translate_directionality_markers, ); let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest); let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags( emitter, - sopts.debugging_opts.diagnostic_handler_flags(can_emit_warnings), + sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings), ); - let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile + let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile { let directory = if let Some(ref directory) = d { directory } else { std::path::Path::new(".") }; @@ -1268,8 +1303,8 @@ pub fn build_session( let profiler = SelfProfiler::new( directory, sopts.crate_name.as_deref(), - sopts.debugging_opts.self_profile_events.as_ref().map(|xs| &xs[..]), - &sopts.debugging_opts.self_profile_counter, + sopts.unstable_opts.self_profile_events.as_ref().map(|xs| &xs[..]), + &sopts.unstable_opts.self_profile_counter, ); match profiler { Ok(profiler) => Some(Arc::new(profiler)), @@ -1283,7 +1318,7 @@ pub fn build_session( }; let mut parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map); - parse_sess.assume_incomplete_release = sopts.debugging_opts.assume_incomplete_release; + parse_sess.assume_incomplete_release = sopts.unstable_opts.assume_incomplete_release; let host_triple = config::host_triple(); let target_triple = sopts.target_triple.triple(); @@ -1302,12 +1337,12 @@ pub fn build_session( local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0); let optimization_fuel = Lock::new(OptimizationFuel { - remaining: sopts.debugging_opts.fuel.as_ref().map_or(0, |i| i.1), + remaining: sopts.unstable_opts.fuel.as_ref().map_or(0, |i| i.1), out_of_fuel: false, }); let print_fuel = AtomicU64::new(0); - let cgu_reuse_tracker = if sopts.debugging_opts.query_dep_graph { + let cgu_reuse_tracker = if sopts.unstable_opts.query_dep_graph { CguReuseTracker::new() } else { CguReuseTracker::new_disabled() @@ -1315,8 +1350,8 @@ pub fn build_session( let prof = SelfProfilerRef::new( self_profiler, - sopts.debugging_opts.time_passes || sopts.debugging_opts.time, - sopts.debugging_opts.time_passes, + sopts.unstable_opts.time_passes || sopts.unstable_opts.time, + sopts.unstable_opts.time_passes, ); let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") { @@ -1358,6 +1393,7 @@ pub fn build_session( miri_unleashed_features: Lock::new(Default::default()), asm_arch, target_features: FxHashSet::default(), + unstable_target_features: FxHashSet::default(), }; validate_commandline_args_with_session_available(&sess); @@ -1397,7 +1433,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } // Do the same for sample profile data. - if let Some(ref path) = sess.opts.debugging_opts.profile_sample_use { + if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use { if !path.exists() { sess.err(&format!( "File `{}` passed to `-C profile-sample-use` does not exist.", @@ -1418,7 +1454,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // Sanitizers can only be used on platforms that we know have working sanitizer codegen. let supported_sanitizers = sess.target.options.supported_sanitizers; - let unsupported_sanitizers = sess.opts.debugging_opts.sanitizer - supported_sanitizers; + let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers; match unsupported_sanitizers.into_iter().count() { 0 => {} 1 => { @@ -1435,13 +1471,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } // Cannot mix and match sanitizers. - let mut sanitizer_iter = sess.opts.debugging_opts.sanitizer.into_iter(); + let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter(); if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) { sess.err(&format!("`-Zsanitizer={first}` is incompatible with `-Zsanitizer={second}`")); } // Cannot enable crt-static with sanitizers on Linux - if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() { + if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() { sess.err( "sanitizer is incompatible with statically linked libc, \ disable it using `-C target-feature=-crt-static`", @@ -1453,19 +1489,25 @@ fn validate_commandline_args_with_session_available(sess: &Session) { if sess.is_sanitizer_cfi_enabled() { sess.err("`-Zsanitizer=cfi` requires `-Clto`"); } - if sess.opts.debugging_opts.virtual_function_elimination { + if sess.opts.unstable_opts.virtual_function_elimination { sess.err("`-Zvirtual-function-elimination` requires `-Clto`"); } } - if sess.opts.debugging_opts.stack_protector != StackProtector::None { + if sess.opts.unstable_opts.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { sess.warn(&format!( "`-Z stack-protector={}` is not supported for target {} and will be ignored", - sess.opts.debugging_opts.stack_protector, sess.opts.target_triple + sess.opts.unstable_opts.stack_protector, sess.opts.target_triple )) } } + + if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version { + if dwarf_version > 5 { + sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version)); + } + } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 955db72157c6a..e169d3c7cfb7c 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -108,7 +108,7 @@ fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) // which will cause us to require that this method always be called with `Span` hashing // enabled. HashingControls { hash_spans } - if hash_spans == !ctx.debug_opts_incremental_ignore_spans() => {} + if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {} other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other), } } @@ -629,8 +629,7 @@ pub fn debug_hygiene_data(verbose: bool) -> String { if verbose { format!("{:#?}", data) } else { - let mut s = String::from(""); - s.push_str("Expansions:"); + let mut s = String::from("Expansions:"); let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| { s.push_str(&format!( "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", @@ -645,7 +644,10 @@ pub fn debug_hygiene_data(verbose: bool) -> String { let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID"); debug_expn_data((&id.to_expn_id(), expn_data)) }); + // Sort the hash map for more reproducible output. + // Because of this, it is fine to rely on the unstable iteration order of the map. + #[allow(rustc::potential_query_instability)] let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect(); foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id)); foreign_expn_data.into_iter().for_each(debug_expn_data); @@ -1142,7 +1144,6 @@ pub enum DesugaringKind { Async, Await, ForLoop, - LetElse, WhileLoop, } @@ -1158,7 +1159,6 @@ impl DesugaringKind { DesugaringKind::YeetExpr => "`do yeet` expression", DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop => "`for` loop", - DesugaringKind::LetElse => "`let...else`", DesugaringKind::WhileLoop => "`while` loop", } } @@ -1211,6 +1211,7 @@ impl HygieneEncodeContext { // It's fine to iterate over a HashMap, because the serialization // of the table that we insert data into doesn't depend on insertion // order + #[allow(rustc::potential_query_instability)] for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| { if self.serialized_ctxts.lock().insert(ctxt) { encode_ctxt(encoder, index, data); @@ -1219,6 +1220,8 @@ impl HygieneEncodeContext { let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) }; + // Same as above, this is fine as we are inserting into a order-independent hashset + #[allow(rustc::potential_query_instability)] for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| { if self.serialized_expns.lock().insert(expn) { encode_expn(encoder, expn, data, hash); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index a329fa153207b..cf30692815147 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -20,7 +20,6 @@ #![feature(negative_impls)] #![feature(min_specialization)] #![feature(rustc_attrs)] -#![allow(rustc::potential_query_instability)] #[macro_use] extern crate rustc_macros; @@ -1603,6 +1602,7 @@ impl SourceFile { self.name.is_real() } + #[inline] pub fn is_imported(&self) -> bool { self.src.is_none() } @@ -2028,9 +2028,9 @@ impl InnerSpan { pub trait HashStableContext { fn def_path_hash(&self, def_id: DefId) -> DefPathHash; fn hash_spans(&self) -> bool; - /// Accesses `sess.opts.debugging_opts.incremental_ignore_spans` since + /// Accesses `sess.opts.unstable_opts.incremental_ignore_spans` since /// we don't have easy access to a `Session` - fn debug_opts_incremental_ignore_spans(&self) -> bool; + fn unstable_opts_incremental_ignore_spans(&self) -> bool; fn def_span(&self, def_id: LocalDefId) -> Span; fn span_data_to_lines_and_cols( &mut self, diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 95ea702961701..afbb88e923360 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -597,6 +597,13 @@ impl SourceMap { local_begin.sf.src.is_some() && local_end.sf.src.is_some() } + pub fn is_span_accessible(&self, sp: Span) -> bool { + self.span_to_source(sp, |src, start_index, end_index| { + Ok(src.get(start_index..end_index).is_some()) + }) + .map_or(false, |is_accessible| is_accessible) + } + /// Returns the source snippet as `String` corresponding to the given `Span`. pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> { self.span_to_source(sp, |src, start_index, end_index| { @@ -956,7 +963,7 @@ impl SourceMap { } pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true).unwrap_or(span); + let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; if let Ok(snippet) = self.span_to_snippet(prev_span) { debug!( "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a6941a451621..d5e65c0b4420a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -135,6 +135,9 @@ symbols! { Arguments, AsMut, AsRef, + AssertParamIsClone, + AssertParamIsCopy, + AssertParamIsEq, AtomicBool, AtomicI128, AtomicI16, @@ -170,6 +173,7 @@ symbols! { DebugTuple, Decodable, Decoder, + DecorateLint, Default, Deref, DiagnosticMessage, @@ -337,6 +341,7 @@ symbols! { always, and, and_then, + anonymous_lifetime_in_impl_trait, any, append_const_msg, arbitrary_enum_discriminant, @@ -455,6 +460,7 @@ symbols! { clone_closures, clone_from, closure, + closure_lifetime_binder, closure_to_fn_coercion, closure_track_caller, cmp, @@ -567,8 +573,10 @@ symbols! { debug_assert_ne_macro, debug_assertions, debug_struct, + debug_struct_fields_finish, debug_trait_builder, debug_tuple, + debug_tuple_fields_finish, debugger_visualizer, decl_macro, declare_lint_pass, @@ -780,6 +788,7 @@ symbols! { impl_lint_pass, impl_macros, impl_trait_in_bindings, + import, import_shadowing, imported_main, in_band_lifetimes, @@ -973,7 +982,6 @@ symbols! { no_link, no_main, no_mangle, - no_niche, no_sanitize, no_stack_check, no_start, @@ -1146,7 +1154,6 @@ symbols! { repr128, repr_align, repr_align_enum, - repr_no_niche, repr_packed, repr_simd, repr_transparent, @@ -1184,6 +1191,7 @@ symbols! { rustc_allocator_nounwind, rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, + rustc_allowed_through_unstable_modules, rustc_attrs, rustc_box, rustc_builtin_macro, @@ -1427,6 +1435,8 @@ symbols! { thumb2, thumb_mode: "thumb-mode", tmm_reg, + to_string, + to_vec, todo_macro, tool_attributes, tool_lints, @@ -1517,6 +1527,7 @@ symbols! { use_nested_groups, used, used_with_arg, + using, usize, v1, va_arg, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index f67b87a6a52b8..e3045c9321d1c 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable}; use rustc_middle::util::common::record_time; use tracing::debug; @@ -96,47 +96,48 @@ fn get_symbol_hash<'tcx>( let substs = instance.substs; debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); - let mut hasher = StableHasher::new(); - let mut hcx = tcx.create_stable_hashing_context(); - - record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); - - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - hcx.while_hashing_spans(false, |hcx| { - item_type.hash_stable(hcx, &mut hasher); - - // If this is a function, we hash the signature as well. - // This is not *strictly* needed, but it may help in some - // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.kind() { - item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher); - } + tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + + record_time(&tcx.sess.perf_stats.symbol_hash_time, || { + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); + + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + hcx.while_hashing_spans(false, |hcx| { + item_type.hash_stable(hcx, &mut hasher); + + // If this is a function, we hash the signature as well. + // This is not *strictly* needed, but it may help in some + // situations, see the `run-make/a-b-a-linker-guard` test. + if let ty::FnDef(..) = item_type.kind() { + item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher); + } - // also include any type parameters (for generic items) - substs.hash_stable(hcx, &mut hasher); + // also include any type parameters (for generic items) + substs.hash_stable(hcx, &mut hasher); - if let Some(instantiating_crate) = instantiating_crate { - tcx.def_path_hash(instantiating_crate.as_def_id()) - .stable_crate_id() - .hash_stable(hcx, &mut hasher); - } + if let Some(instantiating_crate) = instantiating_crate { + tcx.def_path_hash(instantiating_crate.as_def_id()) + .stable_crate_id() + .hash_stable(hcx, &mut hasher); + } - // We want to avoid accidental collision between different types of instances. - // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original - // instances without this. - discriminant(&instance.def).hash_stable(hcx, &mut hasher); + // We want to avoid accidental collision between different types of instances. + // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original + // instances without this. + discriminant(&instance.def).hash_stable(hcx, &mut hasher); + }); }); - }); - // 64 bits should be enough to avoid collisions. - hasher.finish::<u64>() + // 64 bits should be enough to avoid collisions. + hasher.finish::<u64>() + }) } // Follow C++ namespace-mangling style, see diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 1036c5d941ba1..13229a3995c22 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy, + self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy, }; use rustc_span::symbol::kw; use rustc_target::abi::call::FnAbi; @@ -240,7 +240,7 @@ impl<'tcx> SymbolMangler<'tcx> { print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, !>, ) -> Result<&'a mut Self, !> where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { let regions = if value.has_late_bound_regions() { self.tcx.collect_referenced_late_bound_regions(value) diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index df8ccc42a77a3..65d2cd64bf693 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -244,18 +244,8 @@ impl FromStr for InlineAsmArch { } } -#[derive( - Copy, - Clone, - Encodable, - Decodable, - Debug, - Eq, - PartialEq, - PartialOrd, - Hash, - HashStable_Generic -)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum InlineAsmReg { X86(X86InlineAsmReg), Arm(ArmInlineAsmReg), @@ -406,18 +396,8 @@ impl InlineAsmReg { } } -#[derive( - Copy, - Clone, - Encodable, - Decodable, - Debug, - Eq, - PartialEq, - PartialOrd, - Hash, - HashStable_Generic -)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum InlineAsmRegClass { X86(X86InlineAsmRegClass), Arm(ArmInlineAsmRegClass), @@ -620,18 +600,8 @@ impl InlineAsmRegClass { } } -#[derive( - Copy, - Clone, - Encodable, - Decodable, - Debug, - Eq, - PartialEq, - PartialOrd, - Hash, - HashStable_Generic -)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum InlineAsmRegOrRegClass { Reg(InlineAsmReg), RegClass(InlineAsmRegClass), @@ -808,18 +778,8 @@ pub fn allocatable_registers( } } -#[derive( - Copy, - Clone, - Encodable, - Decodable, - Debug, - Eq, - PartialEq, - PartialOrd, - Hash, - HashStable_Generic -)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum InlineAsmClobberAbi { X86, X86_64Win, diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index a8ddcc9bfac64..59dbea7053447 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -8,6 +8,7 @@ //! LLVM. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] #![feature(let_else)] diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 86f76fdb6a7f6..9d36e37d7b82e 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { // FIXME: The leak sanitizer currently fails the tests, see #88132. base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), "arm64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // Clang automatically chooses a more specific target based on diff --git a/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs new file mode 100644 index 0000000000000..1b7161fbb85c5 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs @@ -0,0 +1,26 @@ +use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelroLevel, Target, TargetOptions}; + +const LINKER_SCRIPT: &str = include_str!("./aarch64_nintendo_switch_freestanding_linker_script.ld"); + +/// A base target for Nintendo Switch devices using a pure LLVM toolchain. +pub fn target() -> Target { + Target { + llvm_target: "aarch64-unknown-none".into(), + pointer_width: 64, + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + arch: "aarch64".into(), + options: TargetOptions { + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + linker: Some("rust-lld".into()), + link_script: Some(LINKER_SCRIPT.into()), + os: "horizon".into(), + max_atomic_width: Some(128), + panic_strategy: PanicStrategy::Abort, + position_independent_executables: true, + dynamic_linking: true, + executables: true, + relro_level: RelroLevel::Off, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding_linker_script.ld b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding_linker_script.ld new file mode 100644 index 0000000000000..f3441e6593782 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding_linker_script.ld @@ -0,0 +1,78 @@ +OUTPUT_FORMAT(elf64-littleaarch64) +OUTPUT_ARCH(aarch64) +ENTRY(_start) + +PHDRS +{ + text PT_LOAD FLAGS(5); + rodata PT_LOAD FLAGS(4); + data PT_LOAD FLAGS(6); + bss PT_LOAD FLAGS(6); + dynamic PT_DYNAMIC; +} + +SECTIONS +{ + . = 0; + + .text : ALIGN(0x1000) { + HIDDEN(__text_start = .); + KEEP(*(.text.jmp)) + + . = 0x80; + + *(.text .text.*) + *(.plt .plt.*) + } + + /* Read-only sections */ + + . = ALIGN(0x1000); + + .module_name : { *(.module_name) } :rodata + + .rodata : { *(.rodata .rodata.*) } :rodata + .hash : { *(.hash) } + .dynsym : { *(.dynsym .dynsym.*) } + .dynstr : { *(.dynstr .dynstr.*) } + .rela.dyn : { *(.rela.dyn) } + + .eh_frame : { + HIDDEN(__eh_frame_start = .); + *(.eh_frame .eh_frame.*) + HIDDEN(__eh_frame_end = .); + } + + .eh_frame_hdr : { + HIDDEN(__eh_frame_hdr_start = .); + *(.eh_frame_hdr .eh_frame_hdr.*) + HIDDEN(__eh_frame_hdr_end = .); + } + + /* Read-write sections */ + + . = ALIGN(0x1000); + + .data : { + *(.data .data.*) + *(.got .got.*) + *(.got.plt .got.plt.*) + } :data + + .dynamic : { + HIDDEN(__dynamic_start = .); + *(.dynamic) + } + + /* BSS section */ + + . = ALIGN(0x1000); + + .bss : { + HIDDEN(__bss_start = .); + *(.bss .bss.*) + *(COMMON) + . = ALIGN(8); + HIDDEN(__bss_end = .); + } :bss +} diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index 2c7834c225b64..d3fd7051a1289 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -13,7 +13,6 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), features: "+strict-align,+neon,+fp-armv8".into(), - executables: true, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs index 1b6525a7c69af..6316abe1ba9f2 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), features: "+strict-align,-neon,-fp-armv8".into(), - executables: true, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs index 965b254c2898f..162b091b269ab 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs @@ -2,20 +2,13 @@ // uefi-base module for generic UEFI options. use super::uefi_msvc_base; -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = uefi_msvc_base::opts(); base.max_atomic_width = Some(64); - - let pre_link_args_msvc = vec!["/machine:arm64".into()]; - - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); - base.pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) - .unwrap() - .extend(pre_link_args_msvc); + base.add_pre_link_args(LinkerFlavor::Msvc, &["/machine:arm64"]); Target { llvm_target: "aarch64-unknown-windows".into(), diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index c2b9d696776f5..dc06597db6fd4 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -3,7 +3,7 @@ use crate::spec::TargetOptions; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); base.os = "android".into(); - base.dwarf_version = Some(2); + base.default_dwarf_version = 2; base.position_independent_executables = true; base.has_thread_local = false; // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867 diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index e8460a509e2ba..9bfae46ef32d2 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -25,10 +25,9 @@ pub fn opts(os: &'static str) -> TargetOptions { function_sections: false, dynamic_linking: true, linker_is_gnu: false, - executables: true, families: cvs!["unix"], is_like_osx: true, - dwarf_version: Some(2), + default_dwarf_version: 2, frame_pointer: FramePointer::Always, has_rpath: true, dll_suffix: ".dylib".into(), diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index ecb6cbd9f8a49..0328ea98c48cb 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -54,7 +54,6 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { abi: target_abi(arch).into(), cpu: target_cpu(arch).into(), dynamic_linking: false, - executables: true, link_env_remove: link_env_remove(arch), has_thread_local: false, ..super::apple_base::opts(os) diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs index 0cb18f17310b8..511693abe9807 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { abi: "eabi".into(), endian: Endian::Big, linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), - executables: true, linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs index a5b7c12cc7b9f..5df4a0a1583fb 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { abi: "eabihf".into(), endian: Endian::Big, linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), - executables: true, linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs index 67df73fa93591..1bba3939397b7 100644 --- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs @@ -1,19 +1,13 @@ -use crate::spec::{cvs, LinkArgs, LinkerFlavor, RelocModel, Target, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, RelocModel, Target, TargetOptions}; /// A base target for Nintendo 3DS devices using the devkitARM toolchain. /// /// Requires the devkitARM toolchain for 3DS targets on the host system. pub fn target() -> Target { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( + let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gcc, - vec![ - "-specs=3dsx.specs".into(), - "-mtune=mpcore".into(), - "-mfloat-abi=hard".into(), - "-mtp=soft".into(), - ], + &["-specs=3dsx.specs", "-mtune=mpcore", "-mfloat-abi=hard", "-mtp=soft"], ); Target { @@ -29,7 +23,6 @@ pub fn target() -> Target { abi: "eabihf".into(), linker_flavor: LinkerFlavor::Gcc, cpu: "mpcore".into(), - executables: true, families: cvs!["unix"], linker: Some("arm-none-eabi-gcc".into()), relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs index 2afd93fcad807..38c117a495e60 100644 --- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs @@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::android_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-march=armv7-a"]); Target { llvm_target: "armv7-none-linux-android".into(), pointer_width: 32, diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs index ff649434312d7..cb5cbe15836fe 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs @@ -22,7 +22,6 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(), - executables: true, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs index c0321d0bef4cb..fb5dd2e7574fc 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs @@ -13,7 +13,6 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".into(), - executables: true, relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs index 2c3f79cc58be7..5f1da09b31722 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs @@ -13,7 +13,6 @@ pub fn target() -> Target { options: TargetOptions { abi: "eabi".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), - executables: true, linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs index 5c82e7684834f..0038ed0df8bd3 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs @@ -13,7 +13,6 @@ pub fn target() -> Target { options: TargetOptions { abi: "eabihf".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), - executables: true, linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs index 269bf8b8bcd49..b4cf2c5ee2294 100644 --- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs @@ -2,10 +2,6 @@ use super::{wasm32_unknown_emscripten, LinkerFlavor, Target}; pub fn target() -> Target { let mut target = wasm32_unknown_emscripten::target(); - target.post_link_args.entry(LinkerFlavor::Em).or_default().extend(vec![ - "-sWASM=0".into(), - "--memory-init-file".into(), - "0".into(), - ]); + target.add_post_link_args(LinkerFlavor::Em, &["-sWASM=0", "--memory-init-file", "0"]); target } diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index c288e8b0e9ea3..1d441e558ddcc 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -3,7 +3,8 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; /// A base target for AVR devices using the GNU toolchain. /// /// Requires GNU avr-gcc and avr-binutils on the host system. -pub fn target(target_cpu: &'static str) -> Target { +/// FIXME: Remove the second parameter when const string concatenation is possible. +pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { Target { arch: "avr".into(), data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), @@ -15,12 +16,9 @@ pub fn target(target_cpu: &'static str) -> Target { exe_suffix: ".elf".into(), linker: Some("avr-gcc".into()), - executables: true, eh_frame_header: false, - pre_link_args: [(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu).into()])] - .into_iter() - .collect(), - late_link_args: [(LinkerFlavor::Gcc, vec!["-lgcc".into()])].into_iter().collect(), + pre_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &[mmcu]), + late_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &["-lgcc"]), max_atomic_width: Some(0), atomic_cas: false, ..TargetOptions::default() diff --git a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs index 6871ca0f78936..6c16b03cc283d 100644 --- a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs +++ b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs @@ -1,5 +1,5 @@ use crate::spec::Target; pub fn target() -> Target { - super::avr_gnu_base::target("atmega328") + super::avr_gnu_base::target("atmega328", "-mmcu=atmega328") } diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs index 4fa6e12f5ba86..3c4da6f883d9d 100644 --- a/compiler/rustc_target/src/spec/bpf_base.rs +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -7,7 +7,6 @@ pub fn opts(endian: Endian) -> TargetOptions { endian, linker_flavor: LinkerFlavor::BpfLinker, atomic_cas: false, - executables: true, dynamic_linking: true, no_builtins: true, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs index b59322d07f57a..de2be78179699 100644 --- a/compiler/rustc_target/src/spec/dragonfly_base.rs +++ b/compiler/rustc_target/src/spec/dragonfly_base.rs @@ -4,12 +4,11 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "dragonfly".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, - dwarf_version: Some(2), + default_dwarf_version: 2, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs index a7e0f9f704127..8c141aaaec34a 100644 --- a/compiler/rustc_target/src/spec/freebsd_base.rs +++ b/compiler/rustc_target/src/spec/freebsd_base.rs @@ -4,13 +4,12 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "freebsd".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, abi_return_struct_as_int: true, - dwarf_version: Some(2), + default_dwarf_version: 2, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index b64875e32bdd7..df1e3275f7373 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -1,23 +1,20 @@ -use crate::spec::{ - crt_objects, cvs, LinkArgs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions, -}; +use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( - LinkerFlavor::Lld(LldFlavor::Ld), - vec![ - "--build-id".into(), - "--hash-style=gnu".into(), - "-z".into(), - "max-page-size=4096".into(), - "-z".into(), - "now".into(), - "-z".into(), - "rodynamic".into(), - "-z".into(), - "separate-loadable-segments".into(), - "--pack-dyn-relocs=relr".into(), + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + "--build-id", + "--hash-style=gnu", + "-z", + "max-page-size=4096", + "-z", + "now", + "-z", + "rodynamic", + "-z", + "separate-loadable-segments", + "--pack-dyn-relocs=relr", ], ); @@ -26,7 +23,6 @@ pub fn opts() -> TargetOptions { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), dynamic_linking: true, - executables: true, families: cvs!["unix"], pre_link_args, pre_link_objects: crt_objects::new(&[ diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs index 61c05a2bdb621..8ab874410aa1c 100644 --- a/compiler/rustc_target/src/spec/haiku_base.rs +++ b/compiler/rustc_target/src/spec/haiku_base.rs @@ -4,7 +4,6 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "haiku".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], relro_level: RelroLevel::Full, ..Default::default() diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs index 7cbd42417e6a0..562ccef7eba01 100644 --- a/compiler/rustc_target/src/spec/hermit_base.rs +++ b/compiler/rustc_target/src/spec/hermit_base.rs @@ -1,17 +1,15 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel}; +use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( - LinkerFlavor::Lld(LldFlavor::Ld), - vec!["--build-id".into(), "--hash-style=gnu".into(), "--Bstatic".into()], + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &["--build-id", "--hash-style=gnu", "--Bstatic"], ); TargetOptions { os: "hermit".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".into()), - executables: true, has_thread_local: true, pre_link_args, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs index 80cf09517cc2c..cc2c78c69fe15 100644 --- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs @@ -11,7 +11,6 @@ pub fn target() -> Target { base.has_rpath = true; base.linker_is_gnu = false; base.dynamic_linking = true; - base.executables = true; base.c_enum_min_bits = 8; diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index ad716a6cd5aae..1718bd77b868f 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); base.cpu = "yonah".into(); base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs index 554b0f3449945..6318654399c47 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs @@ -1,19 +1,16 @@ -use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target}; +use crate::spec::{FramePointer, LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "pentium4".into(); - base.pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pe".into()]); base.max_atomic_width = Some(64); base.frame_pointer = FramePointer::Always; // Required for backtraces base.linker = Some("i686-w64-mingw32-gcc".into()); // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args - .entry(LinkerFlavor::Gcc) - .or_default() - .push("-Wl,--large-address-aware".into()); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]); Target { llvm_target: "i686-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs index fb0cb6a69432a..f4ceaa1ca4bb8 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs @@ -1,24 +1,22 @@ -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - let pre_link_args_msvc = vec![ - // Mark all dynamic libraries and executables as compatible with the larger 4GiB address - // space available to x86 Windows binaries on x86_64. - "/LARGEADDRESSAWARE".into(), - // Ensure the linker will only produce an image if it can also produce a table of - // the image's safe exception handlers. - // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers - "/SAFESEH".into(), - ]; - base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); - base.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .extend(pre_link_args_msvc); + base.add_pre_link_args( + LinkerFlavor::Msvc, + &[ + // Mark all dynamic libraries and executables as compatible with the larger 4GiB address + // space available to x86 Windows binaries on x86_64. + "/LARGEADDRESSAWARE", + // Ensure the linker will only produce an image if it can also produce a table of + // the image's safe exception handlers. + // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers + "/SAFESEH", + ], + ); // Workaround for #95429 base.has_thread_local = false; diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index 9f0cb04c65db2..aff284bf2bcf7 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -4,9 +4,7 @@ pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - let pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - pre_link_args.push("-m32".into()); - pre_link_args.push("-Wl,-znotext".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-znotext"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index d1af163f1cff3..87aa74e406c97 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index 0998c618f31a9..765803d169280 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index a697f292da0e2..d9492804349b3 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -4,8 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-Wl,-melf_i386".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-melf_i386"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index 2807d32820540..8de698b51f087 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index 78462eb63b807..7f25a1a16c179 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -4,8 +4,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-fuse-ld=lld".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-fuse-ld=lld"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs index 75f7a2209c8bd..d52810d2fb08b 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs @@ -1,18 +1,15 @@ -use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target}; +use crate::spec::{FramePointer, LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "pentium4".into(); - base.pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pe".into()]); base.max_atomic_width = Some(64); base.frame_pointer = FramePointer::Always; // Required for backtraces // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args - .entry(LinkerFlavor::Gcc) - .or_default() - .push("-Wl,--large-address-aware".into()); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]); Target { llvm_target: "i686-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index d51ed7c1f7aa8..f62404e827936 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs index ef8f90a4da8c4..77e000474b86f 100644 --- a/compiler/rustc_target/src/spec/illumos_base.rs +++ b/compiler/rustc_target/src/spec/illumos_base.rs @@ -1,10 +1,9 @@ -use crate::spec::{cvs, FramePointer, LinkArgs, LinkerFlavor, TargetOptions}; +use crate::spec::{cvs, FramePointer, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut late_link_args = LinkArgs::new(); - late_link_args.insert( + let late_link_args = TargetOptions::link_args( LinkerFlavor::Gcc, - vec![ + &[ // The illumos libc contains a stack unwinding implementation, as // does libgcc_s. The latter implementation includes several // additional symbols that are not always in base libc. To force @@ -15,20 +14,19 @@ pub fn opts() -> TargetOptions { // FIXME: This should be replaced by a more complete and generic // mechanism for controlling the order of library arguments passed // to the linker. - "-lc".into(), + "-lc", // LLVM will insert calls to the stack protector functions // "__stack_chk_fail" and "__stack_chk_guard" into code in native // object files. Some platforms include these symbols directly in // libc, but at least historically these have been provided in // libssp.so on illumos and Solaris systems. - "-lssp".into(), + "-lssp", ], ); TargetOptions { os: "illumos".into(), dynamic_linking: true, - executables: true, has_rpath: true, families: cvs!["unix"], is_like_solaris: true, diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs index 7a051532f82e3..a08756861e5b2 100644 --- a/compiler/rustc_target/src/spec/l4re_base.rs +++ b/compiler/rustc_target/src/spec/l4re_base.rs @@ -5,7 +5,6 @@ pub fn opts() -> TargetOptions { os: "l4re".into(), env: "uclibc".into(), linker_flavor: LinkerFlavor::L4Bender, - executables: true, panic_strategy: PanicStrategy::Abort, linker: Some("l4-bender".into()), linker_is_gnu: false, diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs index 0f79ada0d9332..f4fce3b4050aa 100644 --- a/compiler/rustc_target/src/spec/linux_base.rs +++ b/compiler/rustc_target/src/spec/linux_base.rs @@ -4,7 +4,6 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "linux".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], has_rpath: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs index 03e0934ea5ecc..cfc8ec21c2aef 100644 --- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs @@ -1,13 +1,11 @@ use crate::spec::{cvs, Target, TargetOptions}; -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, RelocModel}; +use crate::spec::{LinkerFlavor, LldFlavor, RelocModel}; // The PSP has custom linker requirements. const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld"); pub fn target() -> Target { - let mut pre_link_args = LinkArgs::new(); - pre_link_args - .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".into(), "--nmagic".into()]); + let pre_link_args = TargetOptions::link_args(LinkerFlavor::Ld, &["--emit-relocs", "--nmagic"]); Target { llvm_target: "mipsel-sony-psp".into(), @@ -20,7 +18,6 @@ pub fn target() -> Target { vendor: "sony".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), cpu: "mips2".into(), - executables: true, linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs index 736af15cf449a..fe2aa2de871ce 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs @@ -17,7 +17,6 @@ pub fn target() -> Target { cpu: "mips32r2".into(), features: "+mips32r2,+soft-float,+noabicalls".into(), max_atomic_width: Some(32), - executables: true, linker: Some("rust-lld".into()), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index da0589cdd2093..1a6bb4a2eaf34 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1035,6 +1035,8 @@ supported_targets! { ("armv6k-nintendo-3ds", armv6k_nintendo_3ds), + ("aarch64-nintendo-switch-freestanding", aarch64_nintendo_switch_freestanding), + ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi), ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf), @@ -1212,8 +1214,7 @@ pub struct TargetOptions { pub dynamic_linking: bool, /// If dynamic linking is available, whether only cdylibs are supported. pub only_cdylib: bool, - /// Whether executables are available on this target. iOS, for example, only allows static - /// libraries. Defaults to false. + /// Whether executables are available on this target. Defaults to true. pub executables: bool, /// Relocation model to use in object file. Corresponds to `llc /// -relocation-model=$relocation_model`. Defaults to `Pic`. @@ -1275,9 +1276,9 @@ pub struct TargetOptions { pub is_like_msvc: bool, /// Whether a target toolchain is like WASM. pub is_like_wasm: bool, - /// Version of DWARF to use if not using the default. + /// Default supported version of DWARF on this platform. /// Useful because some platforms (osx, bsd) only want up to DWARF2. - pub dwarf_version: Option<u32>, + pub default_dwarf_version: u32, /// Whether the linker support GNU-like arguments such as -O. Defaults to true. pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly @@ -1459,6 +1460,44 @@ pub struct TargetOptions { pub supports_stack_protector: bool, } +/// Add arguments for the given flavor and also for its "twin" flavors +/// that have a compatible command line interface. +fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) { + let mut insert = |flavor| { + link_args.entry(flavor).or_default().extend(args.iter().copied().map(Cow::Borrowed)) + }; + insert(flavor); + match flavor { + LinkerFlavor::Ld => insert(LinkerFlavor::Lld(LldFlavor::Ld)), + LinkerFlavor::Msvc => insert(LinkerFlavor::Lld(LldFlavor::Link)), + LinkerFlavor::Lld(LldFlavor::Wasm) => {} + LinkerFlavor::Lld(lld_flavor) => { + panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor) + } + LinkerFlavor::Gcc + | LinkerFlavor::Em + | LinkerFlavor::L4Bender + | LinkerFlavor::BpfLinker + | LinkerFlavor::PtxLinker => {} + } +} + +impl TargetOptions { + fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs { + let mut link_args = LinkArgs::new(); + add_link_args(&mut link_args, flavor, args); + link_args + } + + fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { + add_link_args(&mut self.pre_link_args, flavor, args); + } + + fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { + add_link_args(&mut self.post_link_args, flavor, args); + } +} + impl Default for TargetOptions { /// Creates a set of "sane defaults" for any target. This is still /// incomplete, and if used for compilation, will certainly not work. @@ -1482,7 +1521,7 @@ impl Default for TargetOptions { features: "".into(), dynamic_linking: false, only_cdylib: false, - executables: false, + executables: true, relocation_model: RelocModel::Pic, code_model: None, tls_model: TlsModel::GeneralDynamic, @@ -1501,7 +1540,7 @@ impl Default for TargetOptions { is_like_windows: false, is_like_msvc: false, is_like_wasm: false, - dwarf_version: None, + default_dwarf_version: 4, linker_is_gnu: true, allows_weak_linkage: true, has_rpath: false, @@ -1740,13 +1779,13 @@ impl Target { base.$key_name = s; } } ); - ($key_name:ident, Option<u32>) => ( { + ($key_name:ident, u32) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { if s < 1 || s > 5 { return Err("Not a valid DWARF version number".into()); } - base.$key_name = Some(s as u32); + base.$key_name = s as u32; } } ); ($key_name:ident, Option<u64>) => ( { @@ -2105,7 +2144,7 @@ impl Target { key!(is_like_windows, bool); key!(is_like_msvc, bool); key!(is_like_wasm, bool); - key!(dwarf_version, Option<u32>); + key!(default_dwarf_version, u32); key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); @@ -2349,7 +2388,7 @@ impl ToJson for Target { target_option_val!(is_like_windows); target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); - target_option_val!(dwarf_version); + target_option_val!(default_dwarf_version); target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs index cedacb60f3197..6b09386ae3ee5 100644 --- a/compiler/rustc_target/src/spec/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs @@ -9,7 +9,6 @@ pub fn target() -> Target { options: TargetOptions { c_int_width: "16".into(), - executables: true, // The LLVM backend currently can't generate object files. To // workaround this LLVM generates assembly files which then we feed diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index 00cc9620243da..edb30b72bf68d 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -1,18 +1,12 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; +use crate::spec::{LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions}; pub fn opts() -> TargetOptions { - let pre_link_args_msvc = vec![ - // Suppress the verbose logo and authorship debugging output, which would needlessly - // clog any log files. - "/NOLOGO".into(), - ]; - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone()); - pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc); + // Suppress the verbose logo and authorship debugging output, which would needlessly + // clog any log files. + let pre_link_args = TargetOptions::link_args(LinkerFlavor::Msvc, &["/NOLOGO"]); TargetOptions { linker_flavor: LinkerFlavor::Msvc, - executables: true, is_like_windows: true, is_like_msvc: true, lld_flavor: LldFlavor::Link, diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs index 69016d77cf97b..be94ea234658f 100644 --- a/compiler/rustc_target/src/spec/netbsd_base.rs +++ b/compiler/rustc_target/src/spec/netbsd_base.rs @@ -4,14 +4,13 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "netbsd".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], no_default_libraries: false, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, use_ctors_section: true, - dwarf_version: Some(2), + default_dwarf_version: 2, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index 9d94ed8aa480d..1c5b68001b957 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -26,7 +26,6 @@ pub fn target() -> Target { // Needed to use `dylib` and `bin` crate types and the linker. dynamic_linking: true, - executables: true, // Avoid using dylib because it contain metadata not supported // by LLVM NVPTX backend. diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs index bbd322bb6ce2b..e7db14e05a4ec 100644 --- a/compiler/rustc_target/src/spec/openbsd_base.rs +++ b/compiler/rustc_target/src/spec/openbsd_base.rs @@ -4,14 +4,13 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "openbsd".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], has_rpath: true, abi_return_struct_as_int: true, position_independent_executables: true, frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit... relro_level: RelroLevel::Full, - dwarf_version: Some(2), + default_dwarf_version: 2, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs index 595769c4bfa59..803453c4ac411 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs index 24d5d187e1a76..5413c4f33ff61 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); // ld.so in at least RHEL6 on ppc64 has a bug related to BIND_NOW, so only enable partial RELRO diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs index 0f465ccfe776e..159335eb60735 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs index 491d344aedbcb..b7420d232ca80 100644 --- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "ppc64".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs index b198e667ccc36..a3d1800437139 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "ppc64le".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs index 09e3936db268d..e18ff3be4485a 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "ppc64le".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs index 8a947b091cb70..b84943d23a961 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "ppc64le".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs index c27b84775df4b..516b2de37eaa7 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs @@ -3,12 +3,8 @@ use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); // Extra hint to linker that we are generating secure-PLT code. - base.pre_link_args - .entry(LinkerFlavor::Gcc) - .or_default() - .push("--target=powerpc-unknown-freebsd13.0".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--target=powerpc-unknown-freebsd13.0"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs index 88f61500e3ce3..6686a0bbf04aa 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs index 3ee548750b955..6a250f4b51c90 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mspe".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs index ce33c787f3339..34200c6790670 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs index 998225f4dae1c..60661ef9b5d4f 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs index 76709cec59103..3f24966e06ec7 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs @@ -3,8 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("--secure-plt".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--secure-plt"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs index 7b5d1242c52e3..0f04f41f9e592 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs @@ -3,8 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mspe".into()); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("--secure-plt".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe", "--secure-plt"]); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs index 1878cc3fc11db..468fe478549b2 100644 --- a/compiler/rustc_target/src/spec/redox_base.rs +++ b/compiler/rustc_target/src/spec/redox_base.rs @@ -5,7 +5,6 @@ pub fn opts() -> TargetOptions { os: "redox".into(), env: "relibc".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], has_rpath: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs index 7124e2df9b341..232139db6cad0 100644 --- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(0), atomic_cas: false, - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs index 508982eed6871..3e5d2887f431c 100644 --- a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs @@ -15,7 +15,6 @@ pub fn target() -> Target { max_atomic_width: Some(0), atomic_cas: false, features: "+m".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs index f2bd6249f0a26..99317b9f1185f 100644 --- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs index b46ca159370d0..a5de645c9846f 100644 --- a/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs @@ -15,7 +15,6 @@ pub fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, ..Default::default() diff --git a/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs index 0200862c7e013..03baef65c0d5b 100644 --- a/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs +++ b/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs @@ -26,7 +26,6 @@ pub fn target() -> Target { atomic_cas: true, features: "+m,+c".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs index 4216968cb776a..bf510d204a721 100644 --- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs @@ -15,7 +15,6 @@ pub fn target() -> Target { max_atomic_width: Some(0), atomic_cas: false, features: "+m,+c".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs index 2a93459ef4f74..03b3cfd1eb11c 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs @@ -15,7 +15,6 @@ pub fn target() -> Target { cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+f,+d,+c".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs index 6a8d8a97de641..2a94c9dd23371 100644 --- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs @@ -14,7 +14,6 @@ pub fn target() -> Target { cpu: "generic-rv64".into(), max_atomic_width: Some(64), features: "+m,+a,+c".into(), - executables: true, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, code_model: Some(CodeModel::Medium), diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs index d61e1b2ec1048..b7e8e8cf7f577 100644 --- a/compiler/rustc_target/src/spec/solaris_base.rs +++ b/compiler/rustc_target/src/spec/solaris_base.rs @@ -4,7 +4,6 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "solaris".into(), dynamic_linking: true, - executables: true, has_rpath: true, families: cvs!["unix"], is_like_solaris: true, diff --git a/compiler/rustc_target/src/spec/solid_base.rs b/compiler/rustc_target/src/spec/solid_base.rs index c5602a4513a9a..c585a6cd58ea2 100644 --- a/compiler/rustc_target/src/spec/solid_base.rs +++ b/compiler/rustc_target/src/spec/solid_base.rs @@ -5,6 +5,7 @@ pub fn opts(kernel: &str) -> TargetOptions { TargetOptions { os: format!("solid_{}", kernel).into(), vendor: "kmc".into(), + executables: false, frame_pointer: FramePointer::NonLeaf, has_thread_local: true, ..Default::default() diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs index 718303a4b4d5e..836ab0e37283a 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "v9".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs index 2aaa0ca6df844..4a192df392fa3 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.endian = Endian::Big; base.cpu = "v9".into(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs index 71d3de0bfd1ba..ea4fafa4b0654 100644 --- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.endian = Endian::Big; base.cpu = "v9".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mv8plus".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mv8plus"]); Target { llvm_target: "sparc-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs index 79ae54aa6668f..aac09181a74d1 100644 --- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); base.endian = Endian::Big; - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // llvm calls this "v9" base.cpu = "v9".into(); base.vendor = "sun".into(); diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 0865ca7ea7df0..c7c5a23190102 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -1,4 +1,5 @@ use super::super::*; +use std::assert_matches::assert_matches; // Test target self-consistency and JSON encoding/decoding roundtrip. pub(super) fn test_target(target: Target) { @@ -14,35 +15,105 @@ impl Target { assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64"); assert!(self.is_like_windows || !self.is_like_msvc); - // Check that LLD with the given flavor is treated identically to the linker it emulates. - // If your target really needs to deviate from the rules below, except it and document the - // reasons. - assert_eq!( - self.linker_flavor == LinkerFlavor::Msvc - || self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link), - self.lld_flavor == LldFlavor::Link, - ); - assert_eq!(self.is_like_msvc, self.lld_flavor == LldFlavor::Link); - for args in &[ + // Check that default linker flavor and lld flavor are compatible + // with some other key properties. + assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64)); + assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link)); + assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm)); + assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender)); + assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em)); + assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker)); + assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker)); + + for args in [ &self.pre_link_args, &self.late_link_args, &self.late_link_args_dynamic, &self.late_link_args_static, &self.post_link_args, ] { + for (&flavor, flavor_args) in args { + assert!(!flavor_args.is_empty()); + // Check that flavors mentioned in link args are compatible with the default flavor. + match (self.linker_flavor, self.lld_flavor) { + ( + LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc, + LldFlavor::Ld, + ) => { + assert_matches!( + flavor, + LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc + ) + } + (LinkerFlavor::Gcc, LldFlavor::Ld64) => { + assert_matches!(flavor, LinkerFlavor::Gcc) + } + (LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => { + assert_matches!( + flavor, + LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link) + ) + } + (LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc, LldFlavor::Wasm) => { + assert_matches!( + flavor, + LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc + ) + } + (LinkerFlavor::L4Bender, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::L4Bender) + } + (LinkerFlavor::Em, LldFlavor::Wasm) => { + assert_matches!(flavor, LinkerFlavor::Em) + } + (LinkerFlavor::BpfLinker, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::BpfLinker) + } + (LinkerFlavor::PtxLinker, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::PtxLinker) + } + flavors => unreachable!("unexpected flavor combination: {:?}", flavors), + } + + // Check that link args for cc and non-cc versions of flavors are consistent. + let check_noncc = |noncc_flavor| { + if let Some(noncc_args) = args.get(&noncc_flavor) { + for arg in flavor_args { + if let Some(suffix) = arg.strip_prefix("-Wl,") { + assert!(noncc_args.iter().any(|a| a == suffix)); + } + } + } + }; + match self.linker_flavor { + LinkerFlavor::Gcc => match self.lld_flavor { + LldFlavor::Ld => { + check_noncc(LinkerFlavor::Ld); + check_noncc(LinkerFlavor::Lld(LldFlavor::Ld)); + } + LldFlavor::Wasm => check_noncc(LinkerFlavor::Lld(LldFlavor::Wasm)), + LldFlavor::Ld64 | LldFlavor::Link => {} + }, + _ => {} + } + } + + // Check that link args for lld and non-lld versions of flavors are consistent. + assert_eq!(args.get(&LinkerFlavor::Ld), args.get(&LinkerFlavor::Lld(LldFlavor::Ld))); assert_eq!( args.get(&LinkerFlavor::Msvc), args.get(&LinkerFlavor::Lld(LldFlavor::Link)), ); - if args.contains_key(&LinkerFlavor::Msvc) { - assert_eq!(self.lld_flavor, LldFlavor::Link); - } } + assert!( (self.pre_link_objects_fallback.is_empty() && self.post_link_objects_fallback.is_empty()) || self.crt_objects_fallback.is_some() ); + + // If your target really needs to deviate from the rules below, + // except it and document the reasons. // Keep the default "unknown" vendor instead. assert_ne!(self.vendor, ""); if !self.can_use_os_unknown() { diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs index ef6038e6120b0..049142b89f1f1 100644 --- a/compiler/rustc_target/src/spec/thumb_base.rs +++ b/compiler/rustc_target/src/spec/thumb_base.rs @@ -34,7 +34,6 @@ pub fn opts() -> TargetOptions { // See rust-lang/rfcs#1645 for a discussion about these defaults TargetOptions { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), - executables: true, // In most cases, LLD is good enough linker: Some("rust-lld".into()), // Because these devices have very little resources having an unwinder is too onerous so we diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs index f6cbbd38cf4aa..4d09d3a4d106f 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; +use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::windows_msvc_base::opts(); @@ -9,12 +9,7 @@ pub fn target() -> Target { // should be smart enough to insert branch islands only // where necessary, but this is not the observed behavior. // Disabling the LBR optimization works around the issue. - let pre_link_args_msvc = "/OPT:NOLBR"; - base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().push(pre_link_args_msvc.into()); - base.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .push(pre_link_args_msvc.into()); + base.add_pre_link_args(LinkerFlavor::Msvc, &["/OPT:NOLBR"]); Target { llvm_target: "thumbv7a-pc-windows-msvc".into(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs index 9a3e8b5c5f8f2..4cad9e1837010 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs @@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::android_base::opts(); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-march=armv7-a"]); Target { llvm_target: "armv7-none-linux-android".into(), pointer_width: 32, diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs index bc7244b3a4551..aee8eb2e31c7a 100644 --- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs +++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs @@ -14,27 +14,25 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, Target pub fn opts() -> TargetOptions { let mut base = super::msvc_base::opts(); - let pre_link_args_msvc = vec![ - // Non-standard subsystems have no default entry-point in PE+ files. We have to define - // one. "efi_main" seems to be a common choice amongst other implementations and the - // spec. - "/entry:efi_main".into(), - // COFF images have a "Subsystem" field in their header, which defines what kind of - // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION, - // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION, - // which is very likely the most common option. Individual projects can override this - // with custom linker flags. - // The subsystem-type only has minor effects on the application. It defines the memory - // regions the application is loaded into (runtime-drivers need to be put into - // reserved areas), as well as whether a return from the entry-point is treated as - // exit (default for applications). - "/subsystem:efi_application".into(), - ]; - base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); - base.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .extend(pre_link_args_msvc); + base.add_pre_link_args( + LinkerFlavor::Msvc, + &[ + // Non-standard subsystems have no default entry-point in PE+ files. We have to define + // one. "efi_main" seems to be a common choice amongst other implementations and the + // spec. + "/entry:efi_main", + // COFF images have a "Subsystem" field in their header, which defines what kind of + // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION, + // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION, + // which is very likely the most common option. Individual projects can override this + // with custom linker flags. + // The subsystem-type only has minor effects on the application. It defines the memory + // regions the application is loaded into (runtime-drivers need to be put into + // reserved areas), as well as whether a return from the entry-point is treated as + // exit (default for applications). + "/subsystem:efi_application", + ], + ); TargetOptions { os: "uefi".into(), diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs index 2beb279e39861..aa4784b63e7aa 100644 --- a/compiler/rustc_target/src/spec/vxworks_base.rs +++ b/compiler/rustc_target/src/spec/vxworks_base.rs @@ -8,7 +8,6 @@ pub fn opts() -> TargetOptions { linker: Some("wr-c++".into()), exe_suffix: ".vxe".into(), dynamic_linking: true, - executables: true, families: cvs!["unix"], has_rpath: true, has_thread_local: true, diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index f1087db09d132..c7e7d22108656 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -1,22 +1,12 @@ use super::{cvs, wasm_base}; -use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions}; +use super::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; pub fn target() -> Target { - let mut options = wasm_base::options(); - - let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - - // Rust really needs a way for users to specify exports and imports in - // the source code. --export-dynamic isn't the right tool for this job, - // however it does have the side effect of automatically exporting a lot - // of symbols, which approximates what people want when compiling for - // wasm32-unknown-unknown expect, so use it for now. - clang_args.push("--export-dynamic".into()); - - let mut post_link_args = LinkArgs::new(); - post_link_args.insert( + // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. + let pre_link_args = LinkArgs::new(); + let post_link_args = TargetOptions::link_args( LinkerFlavor::Em, - vec!["-sABORTING_MALLOC=0".into(), "-Wl,--fatal-warnings".into()], + &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], ); let opts = TargetOptions { @@ -26,11 +16,13 @@ pub fn target() -> Target { // functionality, and a .wasm file. exe_suffix: ".js".into(), linker: None, + pre_link_args, + post_link_args, + relocation_model: RelocModel::Pic, panic_strategy: PanicStrategy::Unwind, no_default_libraries: false, - post_link_args, families: cvs!["unix", "wasm"], - ..options + ..wasm_base::options() }; Target { llvm_target: "wasm32-unknown-emscripten".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index 214b5fce5a6b0..4e2927dd913c2 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -29,27 +29,30 @@ pub fn target() -> Target { // code on this target due to this ABI mismatch. options.default_adjusted_cabi = Some(Abi::Wasm); - let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - - // Make sure clang uses LLD as its linker and is configured appropriately - // otherwise - clang_args.push("--target=wasm32-unknown-unknown".into()); - - // For now this target just never has an entry symbol no matter the output - // type, so unconditionally pass this. - clang_args.push("-Wl,--no-entry".into()); - - // Rust really needs a way for users to specify exports and imports in - // the source code. --export-dynamic isn't the right tool for this job, - // however it does have the side effect of automatically exporting a lot - // of symbols, which approximates what people want when compiling for - // wasm32-unknown-unknown expect, so use it for now. - clang_args.push("-Wl,--export-dynamic".into()); - - // Add the flags to wasm-ld's args too. - let lld_args = options.pre_link_args.entry(LinkerFlavor::Lld(LldFlavor::Wasm)).or_default(); - lld_args.push("--no-entry".into()); - lld_args.push("--export-dynamic".into()); + options.add_pre_link_args( + LinkerFlavor::Lld(LldFlavor::Wasm), + &[ + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + "--no-entry", + // Rust really needs a way for users to specify exports and imports in + // the source code. --export-dynamic isn't the right tool for this job, + // however it does have the side effect of automatically exporting a lot + // of symbols, which approximates what people want when compiling for + // wasm32-unknown-unknown expect, so use it for now. + "--export-dynamic", + ], + ); + options.add_pre_link_args( + LinkerFlavor::Gcc, + &[ + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + "--target=wasm32-unknown-unknown", + "-Wl,--no-entry", + "-Wl,--export-dynamic", + ], + ); Target { llvm_target: "wasm32-unknown-unknown".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 10eb78e4e25b7..280457d68b99e 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -80,11 +80,7 @@ pub fn target() -> Target { options.os = "wasi".into(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); - options - .pre_link_args - .entry(LinkerFlavor::Gcc) - .or_insert(Vec::new()) - .push("--target=wasm32-wasi".into()); + options.add_pre_link_args(LinkerFlavor::Gcc, &["--target=wasm32-wasi"]); options.pre_link_objects_fallback = crt_objects::pre_wasi_fallback(); options.post_link_objects_fallback = crt_objects::post_wasi_fallback(); diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs index 6826c0ac62b3a..5211f7707fbb2 100644 --- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs @@ -14,19 +14,25 @@ pub fn target() -> Target { let mut options = wasm_base::options(); options.os = "unknown".into(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); - let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); - // Make sure clang uses LLD as its linker and is configured appropriately - // otherwise - clang_args.push("--target=wasm64-unknown-unknown".into()); - - // For now this target just never has an entry symbol no matter the output - // type, so unconditionally pass this. - clang_args.push("-Wl,--no-entry".into()); - - let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap(); - lld_args.push("--no-entry".into()); - lld_args.push("-mwasm64".into()); + options.add_pre_link_args( + LinkerFlavor::Lld(LldFlavor::Wasm), + &[ + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + "--no-entry", + "-mwasm64", + ], + ); + options.add_pre_link_args( + LinkerFlavor::Gcc, + &[ + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + "--target=wasm64-unknown-unknown", + "-Wl,--no-entry", + ], + ); // Any engine that implements wasm64 will surely implement the rest of these // features since they were all merged into the official spec by the time diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index de7b7374af314..9216d3e7b65f6 100644 --- a/compiler/rustc_target/src/spec/wasm_base.rs +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -1,63 +1,56 @@ use super::crt_objects::CrtObjectsFallback; use super::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; -use std::collections::BTreeMap; pub fn options() -> TargetOptions { - let mut lld_args = Vec::new(); - let mut clang_args = Vec::new(); - let mut arg = |arg: &'static str| { - lld_args.push(arg.into()); - clang_args.push(format!("-Wl,{}", arg).into()); - }; - - // By default LLD only gives us one page of stack (64k) which is a - // little small. Default to a larger stack closer to other PC platforms - // (1MB) and users can always inject their own link-args to override this. - arg("-z"); - arg("stack-size=1048576"); - - // By default LLD's memory layout is: - // - // 1. First, a blank page - // 2. Next, all static data - // 3. Finally, the main stack (which grows down) - // - // This has the unfortunate consequence that on stack overflows you - // corrupt static data and can cause some exceedingly weird bugs. To - // help detect this a little sooner we instead request that the stack is - // placed before static data. - // - // This means that we'll generate slightly larger binaries as references - // to static data will take more bytes in the ULEB128 encoding, but - // stack overflow will be guaranteed to trap as it underflows instead of - // corrupting static data. - arg("--stack-first"); - - // FIXME we probably shouldn't pass this but instead pass an explicit list - // of symbols we'll allow to be undefined. We don't currently have a - // mechanism of knowing, however, which symbols are intended to be imported - // from the environment and which are intended to be imported from other - // objects linked elsewhere. This is a coarse approximation but is sure to - // hide some bugs and frustrate someone at some point, so we should ideally - // work towards a world where we can explicitly list symbols that are - // supposed to be imported and have all other symbols generate errors if - // they remain undefined. - arg("--allow-undefined"); - - // Rust code should never have warnings, and warnings are often - // indicative of bugs, let's prevent them. - arg("--fatal-warnings"); - - // LLD only implements C++-like demangling, which doesn't match our own - // mangling scheme. Tell LLD to not demangle anything and leave it up to - // us to demangle these symbols later. Currently rustc does not perform - // further demangling, but tools like twiggy and wasm-bindgen are intended - // to do so. - arg("--no-demangle"); - - let mut pre_link_args = BTreeMap::new(); - pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); - pre_link_args.insert(LinkerFlavor::Gcc, clang_args); + macro_rules! args { + ($prefix:literal) => { + &[ + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. + concat!($prefix, "-z"), + concat!($prefix, "stack-size=1048576"), + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + concat!($prefix, "--stack-first"), + // FIXME we probably shouldn't pass this but instead pass an explicit list + // of symbols we'll allow to be undefined. We don't currently have a + // mechanism of knowing, however, which symbols are intended to be imported + // from the environment and which are intended to be imported from other + // objects linked elsewhere. This is a coarse approximation but is sure to + // hide some bugs and frustrate someone at some point, so we should ideally + // work towards a world where we can explicitly list symbols that are + // supposed to be imported and have all other symbols generate errors if + // they remain undefined. + concat!($prefix, "--allow-undefined"), + // Rust code should never have warnings, and warnings are often + // indicative of bugs, let's prevent them. + concat!($prefix, "--fatal-warnings"), + // LLD only implements C++-like demangling, which doesn't match our own + // mangling scheme. Tell LLD to not demangle anything and leave it up to + // us to demangle these symbols later. Currently rustc does not perform + // further demangling, but tools like twiggy and wasm-bindgen are intended + // to do so. + concat!($prefix, "--no-demangle"), + ] + }; + } + + let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::Lld(LldFlavor::Wasm), args!("")); + super::add_link_args(&mut pre_link_args, LinkerFlavor::Gcc, args!("-Wl,")); TargetOptions { is_like_wasm: true, @@ -69,9 +62,6 @@ pub fn options() -> TargetOptions { dynamic_linking: true, only_cdylib: true, - // This means we'll just embed a `#[start]` function in the wasm module - executables: true, - // relatively self-explanatory! exe_suffix: ".wasm".into(), dll_prefix: "".into(), diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index d11f1f7d3f856..90e0af3e38afe 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -1,31 +1,35 @@ use crate::spec::crt_objects::{self, CrtObjectsFallback}; -use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( + let mut pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + // Enable ASLR + "--dynamicbase", + // ASLR will rebase it anyway so leaving that option enabled only leads to confusion + "--disable-auto-image-base", + ], + ); + super::add_link_args( + &mut pre_link_args, LinkerFlavor::Gcc, - vec![ + &[ // Tell GCC to avoid linker plugins, because we are not bundling // them with Windows installer, and Rust does its own LTO anyways. - "-fno-use-linker-plugin".into(), - // Enable ASLR - "-Wl,--dynamicbase".into(), - // ASLR will rebase it anyway so leaving that option enabled only leads to confusion - "-Wl,--disable-auto-image-base".into(), + "-fno-use-linker-plugin", + "-Wl,--dynamicbase", + "-Wl,--disable-auto-image-base", ], ); - let mut late_link_args = LinkArgs::new(); - let mut late_link_args_dynamic = LinkArgs::new(); - let mut late_link_args_static = LinkArgs::new(); // Order of `late_link_args*` was found through trial and error to work with various // mingw-w64 versions (not tested on the CI). It's expected to change from time to time. - let mingw_libs = vec![ - "-lmsvcrt".into(), - "-lmingwex".into(), - "-lmingw32".into(), - "-lgcc".into(), // alas, mingw* libraries above depend on libgcc + let mingw_libs = &[ + "-lmsvcrt", + "-lmingwex", + "-lmingw32", + "-lgcc", // alas, mingw* libraries above depend on libgcc // mingw's msvcrt is a weird hybrid import library and static library. // And it seems that the linker fails to use import symbols from msvcrt // that are required from functions in msvcrt in certain cases. For example @@ -33,31 +37,27 @@ pub fn opts() -> TargetOptions { // The library is purposely listed twice to fix that. // // See https://github.com/rust-lang/rust/pull/47483 for some more details. - "-lmsvcrt".into(), - "-luser32".into(), - "-lkernel32".into(), - ]; - late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); - let dynamic_unwind_libs = vec![ - // If any of our crates are dynamically linked then we need to use - // the shared libgcc_s-dw2-1.dll. This is required to support - // unwinding across DLL boundaries. - "-lgcc_s".into(), - ]; - late_link_args_dynamic.insert(LinkerFlavor::Gcc, dynamic_unwind_libs.clone()); - late_link_args_dynamic.insert(LinkerFlavor::Lld(LldFlavor::Ld), dynamic_unwind_libs); - let static_unwind_libs = vec![ - // If all of our crates are statically linked then we can get away - // with statically linking the libgcc unwinding code. This allows - // binaries to be redistributed without the libgcc_s-dw2-1.dll - // dependency, but unfortunately break unwinding across DLL - // boundaries when unwinding across FFI boundaries. - "-lgcc_eh".into(), - "-l:libpthread.a".into(), + "-lmsvcrt", + "-luser32", + "-lkernel32", ]; - late_link_args_static.insert(LinkerFlavor::Gcc, static_unwind_libs.clone()); - late_link_args_static.insert(LinkerFlavor::Lld(LldFlavor::Ld), static_unwind_libs); + let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs); + super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs); + // If any of our crates are dynamically linked then we need to use + // the shared libgcc_s-dw2-1.dll. This is required to support + // unwinding across DLL boundaries. + let dynamic_unwind_libs = &["-lgcc_s"]; + let mut late_link_args_dynamic = + TargetOptions::link_args(LinkerFlavor::Ld, dynamic_unwind_libs); + super::add_link_args(&mut late_link_args_dynamic, LinkerFlavor::Gcc, dynamic_unwind_libs); + // If all of our crates are statically linked then we can get away + // with statically linking the libgcc unwinding code. This allows + // binaries to be redistributed without the libgcc_s-dw2-1.dll + // dependency, but unfortunately break unwinding across DLL + // boundaries when unwinding across FFI boundaries. + let static_unwind_libs = &["-lgcc_eh", "-l:libpthread.a"]; + let mut late_link_args_static = TargetOptions::link_args(LinkerFlavor::Ld, static_unwind_libs); + super::add_link_args(&mut late_link_args_static, LinkerFlavor::Gcc, static_unwind_libs); TargetOptions { os: "windows".into(), @@ -67,7 +67,6 @@ pub fn opts() -> TargetOptions { function_sections: false, linker: Some("gcc".into()), dynamic_linking: true, - executables: true, dll_prefix: "".into(), dll_suffix: ".dll".into(), exe_suffix: ".exe".into(), diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs index 9f9f8be87184e..bae007dc9f3bc 100644 --- a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -1,28 +1,17 @@ -use crate::spec::{cvs, LinkArgs, LinkerFlavor, TargetOptions}; +use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let pre_link_args = LinkArgs::from([( + // We cannot use `-nodefaultlibs` because compiler-rt has to be passed + // as a path since it's not added to linker search path by the default. + // There were attemts to make it behave like libgcc (so one can just use -l<name>) + // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 + let pre_link_args = + TargetOptions::link_args(LinkerFlavor::Gcc, &["-nolibc", "--unwindlib=none"]); + // Order of `late_link_args*` does not matter with LLD. + let late_link_args = TargetOptions::link_args( LinkerFlavor::Gcc, - vec![ - // We cannot use `-nodefaultlibs` because compiler-rt has to be passed - // as a path since it's not added to linker search path by the default. - // There were attemts to make it behave like libgcc (so one can just use -l<name>) - // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 - "-nolibc".into(), - "--unwindlib=none".into(), - ], - )]); - let late_link_args = LinkArgs::from([( - LinkerFlavor::Gcc, - // Order of `late_link_args*` does not matter with LLD. - vec![ - "-lmingw32".into(), - "-lmingwex".into(), - "-lmsvcrt".into(), - "-lkernel32".into(), - "-luser32".into(), - ], - )]); + &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"], + ); TargetOptions { os: "windows".into(), @@ -31,7 +20,6 @@ pub fn opts() -> TargetOptions { abi: "llvm".into(), linker: Some("clang".into()), dynamic_linking: true, - executables: true, dll_prefix: "".into(), dll_suffix: ".dll".into(), exe_suffix: ".exe".into(), diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs index 119683917768b..fa69b919cecd7 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs @@ -1,33 +1,29 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let base = super::windows_gnu_base::opts(); // FIXME: This should be updated for the exception machinery changes from #67502 // and inherit from `windows_gnu_base`, at least partially. - let mut late_link_args = LinkArgs::new(); + let mingw_libs = &[ + "-lwinstorecompat", + "-lruntimeobject", + "-lsynchronization", + "-lvcruntime140_app", + "-lucrt", + "-lwindowsapp", + "-lmingwex", + "-lmingw32", + ]; + let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs); + super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs); + // Reset the flags back to empty until the FIXME above is addressed. let late_link_args_dynamic = LinkArgs::new(); let late_link_args_static = LinkArgs::new(); - let mingw_libs = vec![ - //"-lwinstorecompat".into(), - //"-lmingwex".into(), - //"-lwinstorecompat".into(), - "-lwinstorecompat".into(), - "-lruntimeobject".into(), - "-lsynchronization".into(), - "-lvcruntime140_app".into(), - "-lucrt".into(), - "-lwindowsapp".into(), - "-lmingwex".into(), - "-lmingw32".into(), - ]; - late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); TargetOptions { abi: "uwp".into(), vendor: "uwp".into(), - executables: false, limit_rdylib_exports: false, late_link_args, late_link_args_dynamic, diff --git a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs index d6b065b529a56..f2573fc2d2115 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs @@ -1,16 +1,11 @@ -use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let mut opts = super::windows_msvc_base::opts(); opts.abi = "uwp".into(); opts.vendor = "uwp".into(); - let pre_link_args_msvc = vec!["/APPCONTAINER".into(), "mincore.lib".into()]; - opts.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); - opts.pre_link_args - .entry(LinkerFlavor::Lld(LldFlavor::Link)) - .or_default() - .extend(pre_link_args_msvc); + opts.add_pre_link_args(LinkerFlavor::Msvc, &["/APPCONTAINER", "mincore.lib"]); opts } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index 51d14f0403a55..dbd26899c1899 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -6,8 +6,7 @@ pub fn target() -> Target { base.cpu = "core2".into(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.frame_pointer = FramePointer::Always; - base.pre_link_args - .insert(LinkerFlavor::Gcc, vec!["-m64".into(), "-arch".into(), "x86_64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index 47c70513faf88..9d597ea2e62d6 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -1,41 +1,44 @@ -use std::{borrow::Cow, iter}; +use std::borrow::Cow; use crate::spec::cvs; use super::{LinkerFlavor, LldFlavor, Target, TargetOptions}; pub fn target() -> Target { - const PRE_LINK_ARGS: &[&str] = &[ - "-e", - "elf_entry", - "-Bstatic", - "--gc-sections", - "-z", - "text", - "-z", - "norelro", - "--no-undefined", - "--error-unresolved-symbols", - "--no-undefined-version", - "-Bsymbolic", - "--export-dynamic", - // The following symbols are needed by libunwind, which is linked after - // libstd. Make sure they're included in the link. - "-u", - "__rust_abort", - "-u", - "__rust_c_alloc", - "-u", - "__rust_c_dealloc", - "-u", - "__rust_print_err", - "-u", - "__rust_rwlock_rdlock", - "-u", - "__rust_rwlock_unlock", - "-u", - "__rust_rwlock_wrlock", - ]; + let pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + "-e", + "elf_entry", + "-Bstatic", + "--gc-sections", + "-z", + "text", + "-z", + "norelro", + "--no-undefined", + "--error-unresolved-symbols", + "--no-undefined-version", + "-Bsymbolic", + "--export-dynamic", + // The following symbols are needed by libunwind, which is linked after + // libstd. Make sure they're included in the link. + "-u", + "__rust_abort", + "-u", + "__rust_c_alloc", + "-u", + "__rust_c_dealloc", + "-u", + "__rust_print_err", + "-u", + "__rust_rwlock_rdlock", + "-u", + "__rust_rwlock_unlock", + "-u", + "__rust_rwlock_wrlock", + ], + ); const EXPORT_SYMBOLS: &[&str] = &[ "sgx_entry", @@ -59,18 +62,13 @@ pub fn target() -> Target { vendor: "fortanix".into(), abi: "fortanix".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), - executables: true, linker: Some("rust-lld".into()), max_atomic_width: Some(64), cpu: "x86-64".into(), features: "+rdrnd,+rdseed,+lvi-cfi,+lvi-load-hardening".into(), llvm_args: cvs!["--x86-experimental-lvi-inline-asm-hardening"], position_independent_executables: true, - pre_link_args: iter::once(( - LinkerFlavor::Lld(LldFlavor::Ld), - PRE_LINK_ARGS.iter().cloned().map(Cow::from).collect(), - )) - .collect(), + pre_link_args, override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(Cow::from).collect()), relax_elf_relocations: true, ..Default::default() diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 049cab0d554ec..6d19cf265744e 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { // https://developer.android.com/ndk/guides/abis.html#86-64 base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index 2a697daeb28f8..0550b221fd9ea 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.cpu = "x86-64".into(); base.vendor = "pc".into(); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index 0fa43481c9bbb..59a8cffca480a 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -1,14 +1,11 @@ -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".into(); - let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - gcc_pre_link_args.push("-m64".into()); // Use high-entropy 64 bit address space for ASLR - gcc_pre_link_args.push("-Wl,--high-entropy-va".into()); - base.pre_link_args - .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pep".into()]); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-gcc".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs index b5ff63e0532fd..d3909b3895e52 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs @@ -3,8 +3,7 @@ use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnullvm_base::opts(); base.cpu = "x86-64".into(); - let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - gcc_pre_link_args.push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-clang".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index a02018266fbb2..cbe87589a702d 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, StackProbeType, Target}; pub fn target() -> Target { let mut base = super::solaris_base::opts(); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.cpu = "x86-64".into(); base.vendor = "sun".into(); base.max_atomic_width = Some(64); diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 1f2b998a7ba5f..746f647817801 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index c9aedd6ea82f7..b30784ed69291 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.supported_sanitizers = diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index aebbd18c66a4f..d6d0336298281 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; // This option is required to build executables on Haiku x86_64 diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index 9529fa9640dfa..9f19c3a2b2a91 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, Target}; pub fn target() -> Target { let mut base = super::illumos_base::opts(); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".into(), "-std=c99".into()]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-std=c99"]); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index e525cfdde14fb..956be0353fa39 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.static_position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 863b41633e247..140882747c282 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.abi = "x32".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-mx32"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.has_thread_local = false; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index 8678f06e2cb56..87e7784d1f9e9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.static_position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index a7115dace1c08..d3a67619aa86e 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.supported_sanitizers = SanitizerSet::ADDRESS diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs index 0c510dfaa12c4..809fd642d4114 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs @@ -24,7 +24,6 @@ pub fn target() -> Target { features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" .into(), - executables: true, disable_redzone: true, panic_strategy: PanicStrategy::Abort, code_model: Some(CodeModel::Kernel), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs index 0db88d64ac072..593345a5f1d8c 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { base.features = "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float".into(); base.code_model = Some(CodeModel::Kernel); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); Target { // FIXME: Some dispute, the linux-on-clang folks think this should use diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index 11e9cc4abc0c0..f50c6bceec942 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index af8b9673c3063..668ae90541711 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::redox_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index a94bbbf6edeb9..76d2013cf7fdc 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -1,14 +1,11 @@ -use crate::spec::{LinkerFlavor, LldFlavor, Target}; +use crate::spec::{LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".into(); - let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); - gcc_pre_link_args.push("-m64".into()); // Use high-entropy 64 bit address space for ASLR - gcc_pre_link_args.push("-Wl,--high-entropy-va".into()); - base.pre_link_args - .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".into(), "i386pep".into()]); + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 16d29753e7dc4..1298974952f94 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); - base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".into()); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; base.disable_redzone = true; diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index d59bdae0332cb..aebeb49e623b9 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -23,4 +23,4 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 5b88cff03d7fe..8b7e8984a8adb 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -4,7 +4,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; -use rustc_middle::ty::{ToPredicate, TypeFoldable}; +use rustc_middle::ty::{ToPredicate, TypeVisitable}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f135f0c1b13d2..9d30374f8b8ae 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -9,7 +9,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer use rustc_middle::traits::query::Fallible; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable}; use rustc_span::{Span, DUMMY_SP}; use std::fmt::Debug; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 44ff3fd73061e..c33629192cb2b 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -17,7 +17,7 @@ #![feature(drain_filter)] #![feature(hash_drain_filter)] #![feature(label_break_value)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(if_let_guard)] #![feature(never_type)] @@ -37,5 +37,4 @@ extern crate smallvec; pub mod autoderef; pub mod infer; -pub mod opaque_types; pub mod traits; diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs deleted file mode 100644 index 9dd8588ceceea..0000000000000 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ /dev/null @@ -1,544 +0,0 @@ -use crate::traits; -use crate::traits::error_reporting::InferCtxtExt as _; -use crate::traits::TraitEngineExt as _; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; -use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt as _}; -use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts}; -use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt}; -use rustc_span::Span; - -pub trait InferCtxtExt<'tcx> { - fn infer_opaque_definition_from_instantiation( - &self, - opaque_type_key: OpaqueTypeKey<'tcx>, - instantiated_ty: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, - ) -> Ty<'tcx>; -} - -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { - /// Given the fully resolved, instantiated type for an opaque - /// type, i.e., the value of an inference variable like C1 or C2 - /// (*), computes the "definition type" for an opaque type - /// definition -- that is, the inferred value of `Foo1<'x>` or - /// `Foo2<'x>` that we would conceptually use in its definition: - /// ```ignore (illustrative) - /// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA - /// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB - /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } - /// ``` - /// Note that these values are defined in terms of a distinct set of - /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main - /// purpose of this function is to do that translation. - /// - /// (*) C1 and C2 were introduced in the comments on - /// `register_member_constraints`. Read that comment for more context. - /// - /// # Parameters - /// - /// - `def_id`, the `impl Trait` type - /// - `substs`, the substs used to instantiate this opaque type - /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of - /// `opaque_defn.concrete_ty` - #[instrument(level = "debug", skip(self))] - fn infer_opaque_definition_from_instantiation( - &self, - opaque_type_key: OpaqueTypeKey<'tcx>, - instantiated_ty: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, - ) -> Ty<'tcx> { - if self.is_tainted_by_errors() { - return self.tcx.ty_error(); - } - - let OpaqueTypeKey { def_id, substs } = opaque_type_key; - - // Use substs to build up a reverse map from regions to their - // identity mappings. This is necessary because of `impl - // Trait` lifetimes are computed by replacing existing - // 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(self.tcx, def_id); - debug!(?id_substs); - let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = - substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); - debug!("map = {:#?}", map); - - // Convert the type from the function into a type valid outside - // the function, by replacing invalid regions with 'static, - // after producing an error for each of them. - let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new( - self.tcx, - def_id, - map, - instantiated_ty.ty, - instantiated_ty.span, - )); - debug!(?definition_ty); - - if !check_opaque_type_parameter_valid( - self.tcx, - opaque_type_key, - origin, - instantiated_ty.span, - ) { - return self.tcx.ty_error(); - } - - // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` - // on stable and we'd break that. - if let OpaqueTyOrigin::TyAlias = origin { - // This logic duplicates most of `check_opaque_meets_bounds`. - // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. - let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()); - self.tcx.infer_ctxt().enter(move |infcx| { - // Require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = - ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())) - .to_predicate(infcx.tcx); - let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); - - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // the bounds that the function supplies. - match infcx.register_hidden_type( - OpaqueTypeKey { def_id, substs: id_substs }, - ObligationCause::misc(instantiated_ty.span, body_id), - param_env, - definition_ty, - origin, - ) { - Ok(infer_ok) => { - for obligation in infer_ok.obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - } - Err(err) => { - infcx - .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id, id_substs), - definition_ty, - err, - ) - .emit(); - } - } - - fulfillment_cx.register_predicate_obligation( - &infcx, - Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), - ); - - // Check that all obligations are satisfied by the implementation's - // version. - let errors = fulfillment_cx.select_all_or_error(&infcx); - - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - - if errors.is_empty() { - definition_ty - } else { - infcx.report_fulfillment_errors(&errors, None, false); - self.tcx.ty_error() - } - }) - } else { - definition_ty - } - } -} - -fn check_opaque_type_parameter_valid( - tcx: TyCtxt<'_>, - opaque_type_key: OpaqueTypeKey<'_>, - origin: OpaqueTyOrigin, - span: Span, -) -> bool { - match origin { - // No need to check return position impl trait (RPIT) - // because for type and const parameters they are correct - // by construction: we convert - // - // fn foo<P0..Pn>() -> impl Trait - // - // into - // - // type Foo<P0...Pn> - // fn foo<P0..Pn>() -> Foo<P0...Pn>. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // which would error here on all of the `'static` args. - OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, - // Check these - OpaqueTyOrigin::TyAlias => {} - } - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in opaque_type_key.substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if lt.is_static() => { - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_label( - tcx.def_span(opaque_generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - return false; - } - GenericArgKind::Lifetime(lt) => { - matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo<u32>` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - return false; - } - } - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - return false; - } - } - true -} - -struct ReverseMapper<'tcx> { - tcx: TyCtxt<'tcx>, - - opaque_type_def_id: DefId, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - map_missing_regions_to_empty: bool, - - /// initially `Some`, set to `None` once error has been reported - hidden_ty: Option<Ty<'tcx>>, - - /// Span of function being checked. - span: Span, -} - -impl<'tcx> ReverseMapper<'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - opaque_type_def_id: DefId, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - hidden_ty: Ty<'tcx>, - span: Span, - ) -> Self { - Self { - tcx, - opaque_type_def_id, - map, - map_missing_regions_to_empty: false, - hidden_ty: Some(hidden_ty), - span, - } - } - - fn fold_kind_mapping_missing_regions_to_empty( - &mut self, - kind: GenericArg<'tcx>, - ) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - self.map_missing_regions_to_empty = true; - let kind = kind.fold_with(self); - self.map_missing_regions_to_empty = false; - kind - } - - fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - kind.fold_with(self) - } -} - -impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - #[instrument(skip(self), level = "debug")] - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - // Ignore bound regions and `'static` regions that appear in the - // type, we only need to remap regions that reference lifetimes - // from the function declaration. - // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) | ty::ReStatic => return r, - - // If regions have been erased (by writeback), don't try to unerase - // them. - ty::ReErased => return r, - - // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} - - ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { - // All of the regions in the type should either have been - // erased by writeback, or mapped back to named regions by - // borrow checking. - bug!("unexpected region kind in opaque type: {:?}", r); - } - } - - let generics = self.tcx().generics_of(self.opaque_type_def_id); - match self.map.get(&r.into()).map(|k| k.unpack()) { - Some(GenericArgKind::Lifetime(r1)) => r1, - Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, - None if generics.parent.is_some() => { - if let Some(hidden_ty) = self.hidden_ty.take() { - unexpected_hidden_region_diagnostic( - self.tcx, - self.tcx.def_span(self.opaque_type_def_id), - hidden_ty, - r, - ) - .emit(); - } - self.tcx.lifetimes.re_root_empty - } - None => { - self.tcx - .sess - .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( - self.span, - format!( - "lifetime `{}` is part of concrete type but not used in \ - parameter list of the `impl Trait` type alias", - r - ), - ) - .emit(); - - self.tcx().lifetimes.re_static - } - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_closure(def_id, substs) - } - - ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_generator(def_id, substs, movability) - } - - ty::Param(param) => { - // Look it up in the substitution list. - match self.map.get(&ty.into()).map(|k| k.unpack()) { - // Found it in the substitution list; replace with the parameter from the - // opaque type. - Some(GenericArgKind::Type(t1)) => t1, - Some(u) => panic!("type mapped to unexpected kind: {:?}", u), - None => { - debug!(?param, ?self.map); - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "type parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ty - ), - ) - .emit(); - - self.tcx().ty_error() - } - } - } - - _ => ty.super_fold_with(self), - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - trace!("checking const {:?}", ct); - // Find a const parameter - match ct.kind() { - ty::ConstKind::Param(..) => { - // Look it up in the substitution list. - match self.map.get(&ct.into()).map(|k| k.unpack()) { - // Found it in the substitution list, replace with the parameter from the - // opaque type. - Some(GenericArgKind::Const(c1)) => c1, - Some(u) => panic!("const mapped to unexpected kind: {:?}", u), - None => { - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ct - ), - ) - .emit(); - - self.tcx().const_error(ct.ty()) - } - } - } - - _ => ct, - } - } -} - -/// Given a set of predicates that apply to an object type, returns -/// the region bounds that the (erased) `Self` type must -/// outlive. Precisely *because* the `Self` type is erased, the -/// parameter `erased_self_ty` must be supplied to indicate what type -/// has been used to represent `Self` in the predicates -/// themselves. This should really be a unique type; `FreshTy(0)` is a -/// popular choice. -/// -/// N.B., in some cases, particularly around higher-ranked bounds, -/// this function returns a kind of conservative approximation. -/// That is, all regions returned by this function are definitely -/// required, but there may be other region bounds that are not -/// returned, as well as requirements like `for<'a> T: 'a`. -/// -/// Requires that trait definitions have been processed so that we can -/// elaborate predicates and walk supertraits. -#[instrument(skip(tcx, predicates), level = "debug")] -pub(crate) fn required_region_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - erased_self_ty: Ty<'tcx>, - predicates: impl Iterator<Item = ty::Predicate<'tcx>>, -) -> Vec<ty::Region<'tcx>> { - assert!(!erased_self_ty.has_escaping_bound_vars()); - - traits::elaborate_predicates(tcx, predicates) - .filter_map(|obligation| { - debug!(?obligation); - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Projection(..) - | ty::PredicateKind::Trait(..) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::RegionOutlives(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - if t == &erased_self_ty && !r.has_escaping_bound_vars() { - Some(*r) - } else { - None - } - } - } - }) - .collect() -} diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index a63790b594d83..65ff9ceb67ecb 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -8,6 +8,7 @@ use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{Region, RegionVid, Term}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -212,15 +213,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } - let body_id_map: FxHashMap<_, _> = infcx - .inner - .borrow() - .region_obligations() - .iter() - .map(|&(id, _)| (id, vec![])) - .collect(); - - infcx.process_registered_region_obligations(&body_id_map, None, full_env); + infcx.process_registered_region_obligations(&Default::default(), full_env); let region_data = infcx .inner diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 592b0ab477a39..9ef7ac9a8e04a 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -8,7 +8,7 @@ use crate::traits::{ PredicateObligation, SelectionError, TraitEngine, }; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet<PredicateObligation<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index b37db4b9e1829..52ca23c4b303e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -13,16 +13,15 @@ use crate::traits::{ self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext, }; -//use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, TraitEngine}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; @@ -45,7 +44,7 @@ pub enum Conflict { pub struct OverlapResult<'tcx> { pub impl_header: ty::ImplHeader<'tcx>, - pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, + pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>, /// `true` if the overlap might've been permitted before the shift /// to universes. @@ -317,14 +316,13 @@ fn negative_impl<'cx, 'tcx>( let (subject2, obligations) = impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); - !equate(&infcx, impl_env, impl1_def_id, subject1, subject2, obligations) + !equate(&infcx, impl_env, subject1, subject2, obligations) }) } fn equate<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, impl_env: ty::ParamEnv<'tcx>, - impl1_def_id: DefId, subject1: ImplSubject<'tcx>, subject2: ImplSubject<'tcx>, obligations: impl Iterator<Item = PredicateObligation<'tcx>>, @@ -341,7 +339,7 @@ fn equate<'cx, 'tcx>( let opt_failing_obligation = obligations .into_iter() .chain(more_obligations) - .find(|o| negative_impl_exists(selcx, impl_env, impl1_def_id, o)); + .find(|o| negative_impl_exists(selcx, impl_env, o)); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); @@ -356,18 +354,17 @@ fn equate<'cx, 'tcx>( fn negative_impl_exists<'cx, 'tcx>( selcx: &SelectionContext<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - region_context: DefId, o: &PredicateObligation<'tcx>, ) -> bool { let infcx = &selcx.infcx().fork(); - if resolve_negative_obligation(infcx, param_env, region_context, o) { + if resolve_negative_obligation(infcx, param_env, o) { return true; } // Try to prove a negative obligation exists for super predicates for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { - if resolve_negative_obligation(infcx, param_env, region_context, &o) { + if resolve_negative_obligation(infcx, param_env, &o) { return true; } } @@ -379,7 +376,6 @@ fn negative_impl_exists<'cx, 'tcx>( fn resolve_negative_obligation<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - region_context: DefId, o: &PredicateObligation<'tcx>, ) -> bool { let tcx = infcx.tcx; @@ -397,23 +393,11 @@ fn resolve_negative_obligation<'cx, 'tcx>( return false; } - let mut outlives_env = OutlivesEnvironment::new(param_env); - // FIXME -- add "assumed to be well formed" types into the `outlives_env` - - // "Save" the accumulated implied bounds into the outlives environment - // (due to the FIXME above, there aren't any, but this step is still needed). - // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used - // by the "dummy" causes elsewhere (body-id is only relevant when checking - // function bodies with closures). - outlives_env.save_implied_bounds(CRATE_HIR_ID); - - infcx.process_registered_region_obligations( - outlives_env.region_bound_pairs_map(), - Some(tcx.lifetimes.re_root_empty), - param_env, - ); + // FIXME -- also add "assumed to be well formed" types into the `outlives_env` + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); - let errors = infcx.resolve_regions(region_context, &outlives_env); + let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { return false; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 5d08ea99ac64a..e6284b1c4ace0 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -10,22 +10,153 @@ //! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; -use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; -use rustc_middle::mir; -use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; -use rustc_middle::thir; -use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; -use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::{self, DelaySpanBugEmitted, EarlyBinder, TyCtxt, TypeFoldable}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::ty::abstract_const::{ + walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable, +}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_session::lint; -use rustc_span::def_id::LocalDefId; use rustc_span::Span; -use std::cmp; use std::iter; use std::ops::ControlFlow; +pub struct ConstUnifyCtxt<'tcx> { + pub tcx: TyCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> ConstUnifyCtxt<'tcx> { + // Substitutes generics repeatedly to allow AbstractConsts to unify where a + // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g. + // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] + #[inline] + #[instrument(skip(self), level = "debug")] + fn try_replace_substs_in_root( + &self, + mut abstr_const: AbstractConst<'tcx>, + ) -> Option<AbstractConst<'tcx>> { + while let Node::Leaf(ct) = abstr_const.root(self.tcx) { + match AbstractConst::from_const(self.tcx, ct) { + Ok(Some(act)) => abstr_const = act, + Ok(None) => break, + Err(_) => return None, + } + } + + Some(abstr_const) + } + + /// Tries to unify two abstract constants using structural equality. + #[instrument(skip(self), level = "debug")] + pub fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool { + let a = if let Some(a) = self.try_replace_substs_in_root(a) { + a + } else { + return true; + }; + + let b = if let Some(b) = self.try_replace_substs_in_root(b) { + b + } else { + return true; + }; + + let a_root = a.root(self.tcx); + let b_root = b.root(self.tcx); + debug!(?a_root, ?b_root); + + match (a_root, b_root) { + (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { + let a_ct = a_ct.eval(self.tcx, self.param_env); + debug!("a_ct evaluated: {:?}", a_ct); + let b_ct = b_ct.eval(self.tcx, self.param_env); + debug!("b_ct evaluated: {:?}", b_ct); + + if a_ct.ty() != b_ct.ty() { + return false; + } + + match (a_ct.kind(), b_ct.kind()) { + // We can just unify errors with everything to reduce the amount of + // emitted errors here. + (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, + (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { + a_param == b_param + } + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, + // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]` + // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This + // means that we only allow inference variables if they are equal. + (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, + // We expand generic anonymous constants at the start of this function, so this + // branch should only be taking when dealing with associated constants, at + // which point directly comparing them seems like the desired behavior. + // + // FIXME(generic_const_exprs): This isn't actually the case. + // We also take this branch for concrete anonymous constants and + // expand generic anonymous constants with concrete substs. + (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => { + a_uv == b_uv + } + // FIXME(generic_const_exprs): We may want to either actually try + // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like + // this, for now we just return false here. + _ => false, + } + } + (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { + self.try_unify(a.subtree(al), b.subtree(bl)) + && self.try_unify(a.subtree(ar), b.subtree(br)) + } + (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => { + self.try_unify(a.subtree(av), b.subtree(bv)) + } + (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) + if a_args.len() == b_args.len() => + { + self.try_unify(a.subtree(a_f), b.subtree(b_f)) + && iter::zip(a_args, b_args) + .all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn))) + } + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_kind == b_kind) => + { + self.try_unify(a.subtree(a_operand), b.subtree(b_operand)) + } + // use this over `_ => false` to make adding variants to `Node` less error prone + (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) + | (Node::Leaf(..), _) => false, + } + } +} + +#[instrument(skip(tcx), level = "debug")] +pub fn try_unify_abstract_consts<'tcx>( + tcx: TyCtxt<'tcx>, + (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>), + param_env: ty::ParamEnv<'tcx>, +) -> bool { + (|| { + if let Some(a) = AbstractConst::new(tcx, a)? { + if let Some(b) = AbstractConst::new(tcx, b)? { + let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env }; + return Ok(const_unify_ctxt.try_unify(a, b)); + } + } + + Ok(false) + })() + .unwrap_or_else(|_: ErrorGuaranteed| true) + // FIXME(generic_const_exprs): We should instead have this + // method return the resulting `ty::Const` and return `ConstKind::Error` + // on `ErrorGuaranteed`. +} + /// Check if a given constant can be evaluated. #[instrument(skip(infcx), level = "debug")] pub fn is_const_evaluatable<'cx, 'tcx>( @@ -41,48 +172,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if satisfied_from_param_env(tcx, ct, param_env)? { return Ok(()); } - - // We were unable to unify the abstract constant with - // a constant found in the caller bounds, there are - // now three possible cases here. - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] - enum FailureKind { - /// The abstract const still references an inference - /// variable, in this case we return `TooGeneric`. - MentionsInfer, - /// The abstract const references a generic parameter, - /// this means that we emit an error here. - MentionsParam, - /// The substs are concrete enough that we can simply - /// try and evaluate the given constant. - Concrete, - } - let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) { - Node::Leaf(leaf) => { - if leaf.has_infer_types_or_consts() { - failure_kind = FailureKind::MentionsInfer; - } else if leaf.has_param_types_or_consts() { - failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); - } - - ControlFlow::CONTINUE - } - Node::Cast(_, _, ty) => { - if ty.has_infer_types_or_consts() { - failure_kind = FailureKind::MentionsInfer; - } else if ty.has_param_types_or_consts() { - failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); - } - - ControlFlow::CONTINUE - } - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } - }); - - match failure_kind { + match ct.unify_failure_kind(tcx) { FailureKind::MentionsInfer => { return Err(NotConstEvaluatable::MentionsInfer); } @@ -216,588 +306,3 @@ fn satisfied_from_param_env<'tcx>( Ok(false) } - -/// A tree representing an anonymous constant. -/// -/// This is only able to represent a subset of `MIR`, -/// and should not leak any information about desugarings. -#[derive(Debug, Clone, Copy)] -pub struct AbstractConst<'tcx> { - // FIXME: Consider adding something like `IndexSlice` - // and use this here. - inner: &'tcx [Node<'tcx>], - substs: SubstsRef<'tcx>, -} - -impl<'tcx> AbstractConst<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - uv: ty::Unevaluated<'tcx, ()>, - ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> { - let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; - debug!("AbstractConst::new({:?}) = {:?}", uv, inner); - Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs })) - } - - pub fn from_const( - tcx: TyCtxt<'tcx>, - ct: ty::Const<'tcx>, - ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> { - match ct.kind() { - ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()), - ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported), - _ => Ok(None), - } - } - - #[inline] - pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { - AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs } - } - - #[inline] - pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { - let node = self.inner.last().copied().unwrap(); - match node { - Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)), - Node::Cast(kind, operand, ty) => { - Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs)) - } - // Don't perform substitution on the following as they can't directly contain generic params - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node, - } - } -} - -struct AbstractConstBuilder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - body_id: thir::ExprId, - body: &'a thir::Thir<'tcx>, - /// The current WIP node tree. - nodes: IndexVec<NodeId, Node<'tcx>>, -} - -impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { - fn root_span(&self) -> Span { - self.body.exprs[self.body_id].span - } - - fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> { - let reported = self - .tcx - .sess - .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span, msg) - .help("consider moving this anonymous constant into a `const` function") - .emit(); - - Err(reported) - } - fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> { - let reported = self - .tcx - .sess - .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span, msg) - .help("consider moving this anonymous constant into a `const` function") - .note("this operation may be supported in the future") - .emit(); - - Err(reported) - } - - #[instrument(skip(tcx, body, body_id), level = "debug")] - fn new( - tcx: TyCtxt<'tcx>, - (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), - ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorGuaranteed> { - let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() }; - - struct IsThirPolymorphic<'a, 'tcx> { - is_poly: bool, - thir: &'a thir::Thir<'tcx>, - } - - use crate::rustc_middle::thir::visit::Visitor; - use thir::visit; - - impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { - fn expr_is_poly(&mut self, expr: &thir::Expr<'tcx>) -> bool { - if expr.ty.has_param_types_or_consts() { - return true; - } - - match expr.kind { - thir::ExprKind::NamedConst { substs, .. } => substs.has_param_types_or_consts(), - thir::ExprKind::ConstParam { .. } => true, - thir::ExprKind::Repeat { value, count } => { - self.visit_expr(&self.thir()[value]); - count.has_param_types_or_consts() - } - _ => false, - } - } - - fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool { - if pat.ty.has_param_types_or_consts() { - return true; - } - - match pat.kind.as_ref() { - thir::PatKind::Constant { value } => value.has_param_types_or_consts(), - thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => { - lo.has_param_types_or_consts() || hi.has_param_types_or_consts() - } - _ => false, - } - } - } - - impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { - fn thir(&self) -> &'a thir::Thir<'tcx> { - &self.thir - } - - #[instrument(skip(self), level = "debug")] - fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { - self.is_poly |= self.expr_is_poly(expr); - if !self.is_poly { - visit::walk_expr(self, expr) - } - } - - #[instrument(skip(self), level = "debug")] - fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { - self.is_poly |= self.pat_is_poly(pat); - if !self.is_poly { - visit::walk_pat(self, pat); - } - } - } - - let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body }; - visit::walk_expr(&mut is_poly_vis, &body[body_id]); - debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); - if !is_poly_vis.is_poly { - return Ok(None); - } - - Ok(Some(builder)) - } - - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. - fn check_binop(op: mir::BinOp) -> bool { - use mir::BinOp::*; - match op { - Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le - | Ne | Ge | Gt => true, - Offset => false, - } - } - - /// While we currently allow all unary operations, we still want to explicitly guard against - /// future changes here. - fn check_unop(op: mir::UnOp) -> bool { - use mir::UnOp::*; - match op { - Not | Neg => true, - } - } - - /// Builds the abstract const by walking the thir and bailing out when - /// encountering an unsupported operation. - fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorGuaranteed> { - debug!("Abstractconstbuilder::build: body={:?}", &*self.body); - self.recurse_build(self.body_id)?; - - for n in self.nodes.iter() { - if let Node::Leaf(ct) = n { - if let ty::ConstKind::Unevaluated(ct) = ct.kind() { - // `AbstractConst`s should not contain any promoteds as they require references which - // are not allowed. - assert_eq!(ct.promoted, None); - } - } - } - - Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) - } - - fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorGuaranteed> { - use thir::ExprKind; - let node = &self.body.exprs[node]; - Ok(match &node.kind { - // I dont know if handling of these 3 is correct - &ExprKind::Scope { value, .. } => self.recurse_build(value)?, - &ExprKind::PlaceTypeAscription { source, .. } - | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, - &ExprKind::Literal { lit, neg} => { - let sp = node.span; - let constant = - match self.tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { - Ok(c) => c, - Err(LitToConstError::Reported) => { - self.tcx.const_error(node.ty) - } - Err(LitToConstError::TypeError) => { - bug!("encountered type error in lit_to_const") - } - }; - - self.nodes.push(Node::Leaf(constant)) - } - &ExprKind::NonHirLiteral { lit , user_ty: _} => { - let val = ty::ValTree::from_scalar_int(lit); - self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty))) - } - &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { - let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); - - let constant = self.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Unevaluated(uneval), - ty: node.ty, - }); - - self.nodes.push(Node::Leaf(constant)) - } - - ExprKind::ConstParam {param, ..} => { - let const_param = self.tcx.mk_const(ty::ConstS { - kind: ty::ConstKind::Param(*param), - ty: node.ty, - }); - self.nodes.push(Node::Leaf(const_param)) - } - - ExprKind::Call { fun, args, .. } => { - let fun = self.recurse_build(*fun)?; - - let mut new_args = Vec::<NodeId>::with_capacity(args.len()); - for &id in args.iter() { - new_args.push(self.recurse_build(id)?); - } - let new_args = self.tcx.arena.alloc_slice(&new_args); - self.nodes.push(Node::FunctionCall(fun, new_args)) - } - &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { - let lhs = self.recurse_build(lhs)?; - let rhs = self.recurse_build(rhs)?; - self.nodes.push(Node::Binop(op, lhs, rhs)) - } - &ExprKind::Unary { op, arg } if Self::check_unop(op) => { - let arg = self.recurse_build(arg)?; - self.nodes.push(Node::UnaryOp(op, arg)) - } - // This is necessary so that the following compiles: - // - // ``` - // fn foo<const N: usize>(a: [(); N + 1]) { - // bar::<{ N + 1 }>(); - // } - // ``` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { - self.recurse_build(*e)? - } - // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a - // "coercion cast" i.e. using a coercion or is a no-op. - // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) - &ExprKind::Use { source } => { - let arg = self.recurse_build(source)?; - self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) - } - &ExprKind::Cast { source } => { - let arg = self.recurse_build(source)?; - self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) - } - ExprKind::Borrow{ arg, ..} => { - let arg_node = &self.body.exprs[*arg]; - - // Skip reborrows for now until we allow Deref/Borrow/AddressOf - // expressions. - // FIXME(generic_const_exprs): Verify/explain why this is sound - if let ExprKind::Deref {arg} = arg_node.kind { - self.recurse_build(arg)? - } else { - self.maybe_supported_error( - node.span, - "borrowing is not supported in generic constants", - )? - } - } - // FIXME(generic_const_exprs): We may want to support these. - ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error( - node.span, - "dereferencing or taking the address is not supported in generic constants", - )?, - ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( - node.span, - "array construction is not supported in generic constants", - )?, - ExprKind::Block { .. } => self.maybe_supported_error( - node.span, - "blocks are not supported in generic constant", - )?, - ExprKind::NeverToAny { .. } => self.maybe_supported_error( - node.span, - "converting nevers to any is not supported in generic constant", - )?, - ExprKind::Tuple { .. } => self.maybe_supported_error( - node.span, - "tuple construction is not supported in generic constants", - )?, - ExprKind::Index { .. } => self.maybe_supported_error( - node.span, - "indexing is not supported in generic constant", - )?, - ExprKind::Field { .. } => self.maybe_supported_error( - node.span, - "field access is not supported in generic constant", - )?, - ExprKind::ConstBlock { .. } => self.maybe_supported_error( - node.span, - "const blocks are not supported in generic constant", - )?, - ExprKind::Adt(_) => self.maybe_supported_error( - node.span, - "struct/enum construction is not supported in generic constants", - )?, - // dont know if this is correct - ExprKind::Pointer { .. } => - self.error(node.span, "pointer casts are not allowed in generic constants")?, - ExprKind::Yield { .. } => - self.error(node.span, "generator control flow is not allowed in generic constants")?, - ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self - .error( - node.span, - "loops and loop control flow are not supported in generic constants", - )?, - ExprKind::Box { .. } => - self.error(node.span, "allocations are not allowed in generic constants")?, - - ExprKind::Unary { .. } => unreachable!(), - // we handle valid unary/binary ops above - ExprKind::Binary { .. } => - self.error(node.span, "unsupported binary operation in generic constants")?, - ExprKind::LogicalOp { .. } => - self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, - ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - self.error(node.span, "assignment is not supported in generic constants")? - } - ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( - node.span, - "closures and function keywords are not supported in generic constants", - )?, - // let expressions imply control flow - ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => - self.error(node.span, "control flow is not supported in generic constants")?, - ExprKind::InlineAsm { .. } => { - self.error(node.span, "assembly is not supported in generic constants")? - } - - // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen - ExprKind::VarRef { .. } - | ExprKind::UpvarRef { .. } - | ExprKind::StaticRef { .. } - | ExprKind::ThreadLocalRef(_) => { - self.error(node.span, "unsupported operation in generic constant")? - } - }) - } -} - -/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -pub(super) fn thir_abstract_const<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, -) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> { - if tcx.features().generic_const_exprs { - match tcx.def_kind(def.did) { - // FIXME(generic_const_exprs): We currently only do this for anonymous constants, - // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether - // we want to look into them or treat them as opaque projections. - // - // Right now we do neither of that and simply always fail to unify them. - DefKind::AnonConst | DefKind::InlineConst => (), - _ => return Ok(None), - } - - let body = tcx.thir_body(def)?; - - AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))? - .map(AbstractConstBuilder::build) - .transpose() - } else { - Ok(None) - } -} - -#[instrument(skip(tcx), level = "debug")] -pub(super) fn try_unify_abstract_consts<'tcx>( - tcx: TyCtxt<'tcx>, - (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>), - param_env: ty::ParamEnv<'tcx>, -) -> bool { - (|| { - if let Some(a) = AbstractConst::new(tcx, a)? { - if let Some(b) = AbstractConst::new(tcx, b)? { - let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env }; - return Ok(const_unify_ctxt.try_unify(a, b)); - } - } - - Ok(false) - })() - .unwrap_or_else(|_: ErrorGuaranteed| true) - // FIXME(generic_const_exprs): We should instead have this - // method return the resulting `ty::Const` and return `ConstKind::Error` - // on `ErrorGuaranteed`. -} - -#[instrument(skip(tcx, f), level = "debug")] -pub fn walk_abstract_const<'tcx, R, F>( - tcx: TyCtxt<'tcx>, - ct: AbstractConst<'tcx>, - mut f: F, -) -> ControlFlow<R> -where - F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, -{ - #[instrument(skip(tcx, f), level = "debug")] - fn recurse<'tcx, R>( - tcx: TyCtxt<'tcx>, - ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, - ) -> ControlFlow<R> { - f(ct)?; - let root = ct.root(tcx); - debug!(?root); - match root { - Node::Leaf(_) => ControlFlow::CONTINUE, - Node::Binop(_, l, r) => { - recurse(tcx, ct.subtree(l), f)?; - recurse(tcx, ct.subtree(r), f) - } - Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), - Node::FunctionCall(func, args) => { - recurse(tcx, ct.subtree(func), f)?; - args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) - } - Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), - } - } - - recurse(tcx, ct, &mut f) -} - -struct ConstUnifyCtxt<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl<'tcx> ConstUnifyCtxt<'tcx> { - // Substitutes generics repeatedly to allow AbstractConsts to unify where a - // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g. - // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] - #[inline] - #[instrument(skip(self), level = "debug")] - fn try_replace_substs_in_root( - &self, - mut abstr_const: AbstractConst<'tcx>, - ) -> Option<AbstractConst<'tcx>> { - while let Node::Leaf(ct) = abstr_const.root(self.tcx) { - match AbstractConst::from_const(self.tcx, ct) { - Ok(Some(act)) => abstr_const = act, - Ok(None) => break, - Err(_) => return None, - } - } - - Some(abstr_const) - } - - /// Tries to unify two abstract constants using structural equality. - #[instrument(skip(self), level = "debug")] - fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool { - let a = if let Some(a) = self.try_replace_substs_in_root(a) { - a - } else { - return true; - }; - - let b = if let Some(b) = self.try_replace_substs_in_root(b) { - b - } else { - return true; - }; - - let a_root = a.root(self.tcx); - let b_root = b.root(self.tcx); - debug!(?a_root, ?b_root); - - match (a_root, b_root) { - (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { - let a_ct = a_ct.eval(self.tcx, self.param_env); - debug!("a_ct evaluated: {:?}", a_ct); - let b_ct = b_ct.eval(self.tcx, self.param_env); - debug!("b_ct evaluated: {:?}", b_ct); - - if a_ct.ty() != b_ct.ty() { - return false; - } - - match (a_ct.kind(), b_ct.kind()) { - // We can just unify errors with everything to reduce the amount of - // emitted errors here. - (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, - (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { - a_param == b_param - } - (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, - // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]` - // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This - // means that we only allow inference variables if they are equal. - (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, - // We expand generic anonymous constants at the start of this function, so this - // branch should only be taking when dealing with associated constants, at - // which point directly comparing them seems like the desired behavior. - // - // FIXME(generic_const_exprs): This isn't actually the case. - // We also take this branch for concrete anonymous constants and - // expand generic anonymous constants with concrete substs. - (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => { - a_uv == b_uv - } - // FIXME(generic_const_exprs): We may want to either actually try - // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like - // this, for now we just return false here. - _ => false, - } - } - (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { - self.try_unify(a.subtree(al), b.subtree(bl)) - && self.try_unify(a.subtree(ar), b.subtree(br)) - } - (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => { - self.try_unify(a.subtree(av), b.subtree(bv)) - } - (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) - if a_args.len() == b_args.len() => - { - self.try_unify(a.subtree(a_f), b.subtree(b_f)) - && iter::zip(a_args, b_args) - .all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn))) - } - (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) - if (a_ty == b_ty) && (a_kind == b_kind) => - { - self.try_unify(a.subtree(a_operand), b.subtree(b_operand)) - } - // use this over `_ => false` to make adding variants to `Node` less error prone - (Node::Cast(..), _) - | (Node::FunctionCall(..), _) - | (Node::UnaryOp(..), _) - | (Node::Binop(..), _) - | (Node::Leaf(..), _) => false, - } - } -} diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 4d4778869794b..0f7dc6a1257e5 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -1,18 +1,122 @@ -use rustc_middle::ty::TyCtxt; +use std::cell::RefCell; use super::TraitEngine; use super::{ChalkFulfillmentContext, FulfillmentContext}; +use crate::infer::InferCtxtExt; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::traits::{ + FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, +}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; pub trait TraitEngineExt<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box<Self>; + + fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self>; } impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Box<Self> { - if tcx.sess.opts.debugging_opts.chalk { + if tcx.sess.opts.unstable_opts.chalk { Box::new(ChalkFulfillmentContext::new()) } else { Box::new(FulfillmentContext::new()) } } + + fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self> { + if tcx.sess.opts.unstable_opts.chalk { + Box::new(ChalkFulfillmentContext::new()) + } else { + Box::new(FulfillmentContext::new_ignoring_regions()) + } + } +} + +/// Used if you want to have pleasant experience when dealing +/// with obligations outside of hir or mir typeck. +pub struct ObligationCtxt<'a, 'tcx> { + pub infcx: &'a InferCtxt<'a, 'tcx>, + engine: RefCell<Box<dyn TraitEngine<'tcx>>>, +} + +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) } + } + + pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { + self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); + } + + pub fn register_obligations( + &self, + obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, + ) { + // Can't use `register_predicate_obligations` because the iterator + // may also use this `ObligationCtxt`. + for obligation in obligations { + self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation) + } + } + + pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T { + let InferOk { value, obligations } = infer_ok; + self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations); + value + } + + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). + pub fn register_bound( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + ) { + let tcx = self.infcx.tcx; + let trait_ref = ty::TraitRef { def_id, substs: tcx.mk_substs_trait(ty, &[]) }; + self.register_obligation(Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + }); + } + + pub fn normalize<T: TypeFoldable<'tcx>>( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> T { + let infer_ok = self.infcx.partially_normalize_associated_types_in(cause, param_env, value); + self.register_infer_ok_obligations(infer_ok) + } + + pub fn equate_types( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + ) -> Result<(), TypeError<'tcx>> { + match self.infcx.at(cause, param_env).eq(expected, actual) { + Ok(InferOk { obligations, value: () }) => { + self.register_obligations(obligations); + Ok(()) + } + Err(e) => Err(e), + } + } + + pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> { + self.engine.borrow_mut().select_all_or_error(self.infcx) + } } 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 af0803fbd5414..8a679ca005f3d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -24,12 +24,13 @@ use rustc_hir::Item; use rustc_hir::Node; use rustc_infer::infer::error_reporting::same_type_modulo_infer; use rustc_infer::traits::TraitEngine; -use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::traits::select::OverflowError; +use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, + TypeVisitable, }; use rustc_span::symbol::{kw, sym}; use rustc_span::{ExpnKind, Span, DUMMY_SP}; @@ -484,10 +485,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(span, explanation); } - if let ObligationCauseCode::ObjectCastObligation(obj_ty) = obligation.cause.code().peel_derives() && - let Some(self_ty) = trait_predicate.self_ty().no_bound_vars() && + if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() && Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { - self.suggest_borrowing_for_object_cast(&mut err, &obligation, self_ty, *obj_ty); + self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); } if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { @@ -665,6 +665,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_restricting_param_bound( &mut err, trait_predicate, + None, obligation.cause.body_id, ); } else if !suggested { @@ -673,6 +674,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if !self.report_similar_impl_candidates( impl_candidates, trait_ref, + obligation.cause.body_id, &mut err, ) { // This is *almost* equivalent to @@ -707,6 +709,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.report_similar_impl_candidates( impl_candidates, trait_ref, + obligation.cause.body_id, &mut err, ); } @@ -821,10 +824,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { let found_kind = self.closure_kind(closure_substs).unwrap(); - let closure_span = - self.tcx.sess.source_map().guess_head_span( - self.tcx.hir().span_if_local(closure_def_id).unwrap(), - ); + let closure_span = self.tcx.def_span(closure_def_id); let mut err = struct_span_err!( self.tcx.sess, closure_span, @@ -882,7 +882,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } ty::PredicateKind::WellFormed(ty) => { - if !self.tcx.sess.opts.debugging_opts.chalk { + if !self.tcx.sess.opts.unstable_opts.chalk { // WF predicates cannot themselves make // errors. They can only block due to // ambiguity; otherwise, they always @@ -949,9 +949,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => None, }; - let found_span = found_did - .and_then(|did| self.tcx.hir().span_if_local(did)) - .map(|sp| self.tcx.sess.source_map().guess_head_span(sp)); // the sp could be an fn def + let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did)); if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { // We check closures twice, with obligations flowing in different directions, @@ -1084,10 +1082,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let hir = self.tcx.hir(); Some(match node { Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure { body, fn_decl_span, .. }, + kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }), .. }) => ( - sm.guess_head_span(fn_decl_span), + fn_decl_span, hir.body(body) .params .iter() @@ -1112,18 +1110,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) .collect::<Option<Vec<ArgKind>>>()?, ), - Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) - | Node::ImplItem(&hir::ImplItem { - span, - kind: hir::ImplItemKind::Fn(ref sig, _), - .. - }) + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. }) | Node::TraitItem(&hir::TraitItem { - span, - kind: hir::TraitItemKind::Fn(ref sig, _), - .. + kind: hir::TraitItemKind::Fn(ref sig, _), .. }) => ( - sm.guess_head_span(span), + sig.span, sig.decl .inputs .iter() @@ -1138,7 +1130,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ), Node::Ctor(ref variant_data) => { let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); - let span = sm.guess_head_span(span); (span, vec![ArgKind::empty(); variant_data.fields().len()]) } _ => panic!("non-FnLike node found: {:?}", node), @@ -1360,6 +1351,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { &self, impl_candidates: Vec<ImplCandidate<'tcx>>, trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, err: &mut Diagnostic, ) -> bool; @@ -1560,7 +1552,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { obligation.cause.code().peel_derives(), ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) + | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( @@ -1742,6 +1734,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { &self, impl_candidates: Vec<ImplCandidate<'tcx>>, trait_ref: ty::PolyTraitRef<'tcx>, + body_id: hir::HirId, err: &mut Diagnostic, ) -> bool { let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| { @@ -1812,8 +1805,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { || self.tcx.is_builtin_derive(def_id) }) .filter_map(|def_id| self.tcx.impl_trait_ref(def_id)) - // Avoid mentioning type parameters. - .filter(|trait_ref| !matches!(trait_ref.self_ty().kind(), ty::Param(_))) + .filter(|trait_ref| { + let self_ty = trait_ref.self_ty(); + // Avoid mentioning type parameters. + if let ty::Param(_) = self_ty.kind() { + false + } + // Avoid mentioning types that are private to another crate + else if let ty::Adt(def, _) = self_ty.peel_refs().kind() { + // FIXME(compiler-errors): This could be generalized, both to + // be more granular, and probably look past other `#[fundamental]` + // types, too. + self.tcx + .visibility(def.did()) + .is_accessible_from(body_id.owner.to_def_id(), self.tcx) + } else { + true + } + }) .collect(); return report(normalized_impl_candidates, err); } @@ -1959,26 +1968,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { if predicate.references_error() { return; } - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // Pick the first substitution that still contains inference variables as the one - // we're going to emit an error for. If there are none (see above), fall back to - // the substitution for `Self`. - let subst = { - let substs = data.trait_ref.substs; - substs - .iter() - .find(|s| s.has_infer_types_or_consts()) - .unwrap_or_else(|| substs[0]) - }; // This is kind of a hack: it frequently happens that some earlier // error prevents types from being fully inferred, and then we get @@ -2000,27 +1989,41 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.emit_inference_failure_err( body_id, span, - subst, - vec![], + trait_ref.self_ty().skip_binder().into(), ErrorCode::E0282, + false, ) .emit(); } return; } - let impl_candidates = self - .find_similar_impl_candidates(trait_ref) - .into_iter() - .map(|candidate| candidate.trait_ref) - .collect(); - let mut err = self.emit_inference_failure_err( - body_id, - span, - subst, - impl_candidates, - ErrorCode::E0283, - ); + // Typically, this ambiguity should only happen if + // there are unresolved type inference variables + // (otherwise it would suggest a coherence + // failure). But given #21974 that is not necessarily + // the case -- we can have multiple where clauses that + // are only distinguished by a region, which results + // in an ambiguity even when all types are fully + // known, since we don't dispatch based on region + // relationships. + + // Pick the first substitution that still contains inference variables as the one + // we're going to emit an error for. If there are none (see above), fall back to + // a more general error. + let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts()); + + let mut err = if let Some(subst) = subst { + self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true) + } else { + struct_span_err!( + self.tcx.sess, + span, + E0283, + "type annotations needed: cannot satisfy `{}`", + predicate, + ) + }; let obligation = Obligation::new( obligation.cause.clone(), @@ -2079,6 +2082,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { // | // = note: cannot satisfy `_: Tt` + // Clear any more general suggestions in favor of our specific one + err.clear_suggestions(); + err.span_suggestion_verbose( span.shrink_to_hi(), &format!( @@ -2111,7 +2117,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { return; } - self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282) + self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false) } ty::PredicateKind::Subtype(data) => { @@ -2125,26 +2131,30 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282) + self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true) } ty::PredicateKind::Projection(data) => { - let self_ty = data.projection_ty.self_ty(); - let term = data.term; if predicate.references_error() || self.is_tainted_by_errors() { return; } - if self_ty.needs_infer() && term.needs_infer() { - // We do this for the `foo.collect()?` case to produce a suggestion. + let subst = data + .projection_ty + .substs + .iter() + .chain(Some(data.term.into_arg())) + .find(|g| g.has_infer_types_or_consts()); + if let Some(subst) = subst { let mut err = self.emit_inference_failure_err( body_id, span, - self_ty.into(), - vec![], + subst, ErrorCode::E0284, + true, ); err.note(&format!("cannot satisfy `{}`", predicate)); err } else { + // If we can't find a substitution, just print a generic error let mut err = struct_span_err!( self.tcx.sess, span, @@ -2157,6 +2167,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } } + ty::PredicateKind::ConstEvaluatable(data) => { + if predicate.references_error() || self.is_tainted_by_errors() { + return; + } + let subst = data.substs.iter().find(|g| g.has_infer_types_or_consts()); + if let Some(subst) = subst { + let err = self.emit_inference_failure_err( + body_id, + span, + subst, + ErrorCode::E0284, + true, + ); + err + } else { + // If we can't find a substitution, just print a generic error + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ); + err.span_label(span, &format!("cannot satisfy `{}`", predicate)); + err + } + } _ => { if self.tcx.sess.has_errors().is_some() || self.is_tainted_by_errors() { return; @@ -2187,7 +2224,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let mut post = vec![]; for def_id in impls { match self.tcx.span_of_impl(*def_id) { - Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)), + Ok(span) => spans.push(span), Err(name) => { crates.push(name); if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) { @@ -2534,8 +2571,7 @@ pub fn recursive_type_with_infinite_size_error<'tcx>( spans: Vec<(Span, Option<hir::HirId>)>, ) { assert!(type_def_id.is_local()); - let span = tcx.hir().span_if_local(type_def_id).unwrap(); - let span = tcx.sess.source_map().guess_head_span(span); + let span = tcx.def_span(type_def_id); let path = tcx.def_path_str(type_def_id); let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path); 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 7c9ee64a0c2b0..7e8872d901828 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 @@ -103,7 +103,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) }), hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure { body, movability, .. }, + kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }), .. }) => self.describe_generator(*body).or_else(|| { Some(if movability.is_some() { "an async closure" } else { "a closure" }) 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 fbe66d7dcdd2b..bca80e7ab8abf 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -24,7 +24,8 @@ use rustc_middle::hir::map; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, - ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; @@ -172,6 +173,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, + proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>, body_id: hir::HirId, ); @@ -457,6 +459,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, + proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>, body_id: hir::HirId, ) { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); @@ -589,9 +592,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } // Missing generic type parameter bound. let param_name = self_ty.to_string(); - let constraint = with_no_trimmed_paths!( + let mut constraint = with_no_trimmed_paths!( trait_pred.print_modifiers_and_trait_path().to_string() ); + + if let Some(proj_pred) = proj_pred { + let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder(); + let item = self.tcx.associated_item(projection_ty.item_def_id); + + // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. + // That should be extracted into a helper function. + if constraint.ends_with('>') { + constraint = format!( + "{}, {}={}>", + &constraint[..constraint.len() - 1], + item.name, + term.to_string() + ); + } else { + constraint.push_str(&format!("<{}={}>", item.name, term.to_string())); + } + } + if suggest_constraining_type_param( self.tcx, generics, @@ -777,6 +799,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Ok( EvaluationResult::EvaluatedToOk | EvaluationResult::EvaluatedToOkModuloRegions + | EvaluationResult::EvaluatedToOkModuloOpaqueTypes | EvaluationResult::EvaluatedToAmbig, ) => {} _ => return false, @@ -785,7 +808,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Get the name of the callable and the arguments to be used in the suggestion. let (snippet, sugg) = match hir.get_if_local(def_id) { Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure { fn_decl, fn_decl_span, .. }, + kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }), .. })) => { err.span_label(*fn_decl_span, "consider calling this closure"); @@ -1310,7 +1333,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { visitor.visit_body(&body); let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); - let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id) else { return false; }; + let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; let ret_types = visitor .returns @@ -1542,7 +1565,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::Generator(..) => "generator", _ => "function", }; - let span = self.tcx.sess.source_map().guess_head_span(span); let mut err = struct_span_err!( self.tcx.sess, span, @@ -2204,8 +2226,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => true, }; if !ident.span.overlaps(span) && !same_line { - multispan - .push_span_label(ident.span, "required by a bound in this".to_string()); + multispan.push_span_label(ident.span, "required by a bound in this"); } } let descr = format!("required by a bound in `{}`", item_name); @@ -2217,9 +2238,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_note(tcx.def_span(item_def_id), &descr); } } - ObligationCauseCode::ObjectCastObligation(object_ty) => { + ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => { err.note(&format!( - "required for the cast to the object type `{}`", + "required for the cast from `{}` to the object type `{}`", + self.ty_to_string(concrete_ty), self.ty_to_string(object_ty) )); } @@ -2825,7 +2847,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'tcx>, ) { let rhs_span = match obligation.cause.code() { - ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit } if *is_lit => span, + ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span, _ => return, }; match ( diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d61166437d75e..81f5dcc45b93e 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,11 +6,11 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce use rustc_infer::traits::ProjectionCacheKey; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::thir::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; -use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable}; use std::marker::PhantomData; use super::const_evaluatable; @@ -131,8 +131,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); - let mut errors = Vec::new(); - // Process pending obligations. let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor { selcx, @@ -142,7 +140,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. - errors.extend(outcome.errors.into_iter().map(to_fulfillment_error)); + let errors: Vec<FulfillmentError<'tcx>> = + outcome.errors.into_iter().map(to_fulfillment_error).collect(); debug!( "select({} predicates remaining, {} errors) done", @@ -604,7 +603,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { ), (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { span_bug!( - obligation.cause.span(self.selcx.tcx()), + obligation.cause.span(), "ConstEquate: const_eval_resolve returned an unexpected error" ) } @@ -728,7 +727,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } return ProcessResult::Changed(vec![]); } else { - tracing::debug!("Does NOT hold: {:?}", obligation); + debug!("Does NOT hold: {:?}", obligation); } } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index f04f527ccb7af..dd2769c718698 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -5,7 +5,7 @@ use crate::traits::{self, ObligationCause}; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use crate::traits::error_reporting::InferCtxtExt; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 34b0f431b8e2d..a14bf72242bed 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -32,6 +32,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; use rustc_span::{sym, Span}; use smallvec::SmallVec; @@ -46,7 +47,7 @@ pub use self::SelectionError::*; pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; -pub use self::engine::TraitEngineExt; +pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; @@ -198,17 +199,13 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( } } +#[instrument(level = "debug", skip(tcx, elaborated_env))] fn do_normalize_predicates<'tcx>( tcx: TyCtxt<'tcx>, - region_context: DefId, cause: ObligationCause<'tcx>, elaborated_env: ty::ParamEnv<'tcx>, predicates: Vec<ty::Predicate<'tcx>>, ) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> { - debug!( - "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})", - predicates, region_context, cause, - ); let span = cause.span; tcx.infer_ctxt().enter(|infcx| { // FIXME. We should really... do something with these region @@ -240,38 +237,46 @@ fn do_normalize_predicates<'tcx>( // cares about declarations like `'a: 'b`. let outlives_env = OutlivesEnvironment::new(elaborated_env); - infcx.resolve_regions_and_report_errors(region_context, &outlives_env); + // FIXME: It's very weird that we ignore region obligations but apparently + // still need to use `resolve_regions` as we need the resolved regions in + // the normalized predicates. + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + tcx.sess.delay_span_bug( + span, + format!( + "failed region resolution while normalizing {elaborated_env:?}: {errors:?}" + ), + ); + } - let predicates = match infcx.fully_resolve(predicates) { - Ok(predicates) => predicates, + match infcx.fully_resolve(predicates) { + Ok(predicates) => Ok(predicates), Err(fixup_err) => { // If we encounter a fixup error, it means that some type // variable wound up unconstrained. I actually don't know // if this can happen, and I certainly don't expect it to // happen often, but if it did happen it probably // represents a legitimate failure due to some kind of - // unconstrained variable, and it seems better not to ICE, - // all things considered. - let reported = tcx.sess.span_err(span, &fixup_err.to_string()); - return Err(reported); + // unconstrained variable. + // + // @lcnr: Let's still ICE here for now. I want a test case + // for that. + span_bug!( + span, + "inference variables in normalized parameter environment: {}", + fixup_err + ); } - }; - if predicates.needs_infer() { - let reported = tcx - .sess - .delay_span_bug(span, "encountered inference variables after `fully_resolve`"); - Err(reported) - } else { - Ok(predicates) } }) } // FIXME: this is gonna need to be removed ... /// Normalizes the parameter environment, reporting errors if they occur. +#[instrument(level = "debug", skip(tcx))] pub fn normalize_param_env_or_error<'tcx>( tcx: TyCtxt<'tcx>, - region_context: DefId, unnormalized_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, ) -> ty::ParamEnv<'tcx> { @@ -289,12 +294,6 @@ pub fn normalize_param_env_or_error<'tcx>( // parameter environments once for every fn as it goes, // and errors will get reported then; so outside of type inference we // can be sure that no errors should occur. - - debug!( - "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})", - region_context, unnormalized_env, cause - ); - let mut predicates: Vec<_> = util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()) .map(|obligation| obligation.predicate) @@ -338,7 +337,6 @@ pub fn normalize_param_env_or_error<'tcx>( ); let Ok(non_outlives_predicates) = do_normalize_predicates( tcx, - region_context, cause.clone(), elaborated_env, predicates, @@ -362,7 +360,6 @@ pub fn normalize_param_env_or_error<'tcx>( ); let Ok(outlives_predicates) = do_normalize_predicates( tcx, - region_context, cause, outlives_env, outlives_predicates, @@ -856,20 +853,6 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, - 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 { - const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) - } - }, - thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { - const_evaluatable::thir_abstract_const( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - ) - }, try_unify_abstract_consts: |tcx, param_env_and| { let (param_env, (a, b)) = param_env_and.into_parts(); const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 132c335a7e65d..2921ce0ffefe1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -11,15 +11,15 @@ use super::elaborate_predicates; use crate::infer::TyCtxtInferExt; -use crate::traits::const_evaluatable::{self, AbstractConst}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst}; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor, + self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -366,15 +366,9 @@ fn object_safety_violation_for_method( // Get an accurate span depending on the violation. violation.map(|v| { let node = tcx.hir().get_if_local(method.def_id); - let span = match (v, node) { - (MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node - .fn_decl() - .and_then(|decl| decl.inputs.get(arg + 1)) - .map_or(method.ident(tcx).span, |arg| arg.span), - (MethodViolationCode::UndispatchableReceiver, Some(node)) => node - .fn_decl() - .and_then(|decl| decl.inputs.get(0)) - .map_or(method.ident(tcx).span, |arg| arg.span), + let span = match (&v, node) { + (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, + (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span()) } @@ -397,32 +391,41 @@ fn virtual_call_violation_for_method<'tcx>( // The method's first parameter must be named `self` if !method.fn_has_self_parameter { - // We'll attempt to provide a structured suggestion for `Self: Sized`. - let sugg = - tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map( - |generics| match generics.predicates { - [] => (" where Self: Sized", generics.where_clause_span), - [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()), - }, - ); - // Get the span pointing at where the `self` receiver should be. - let sm = tcx.sess.source_map(); - let self_span = method.ident(tcx).span.to(tcx - .hir() - .span_if_local(method.def_id) - .unwrap_or_else(|| sm.next_point(method.ident(tcx).span)) - .shrink_to_hi()); - let self_span = sm.span_through_char(self_span, '(').shrink_to_hi(); - return Some(MethodViolationCode::StaticMethod( - sugg, - self_span, - !sig.inputs().skip_binder().is_empty(), - )); + let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem { + generics, + kind: hir::TraitItemKind::Fn(sig, _), + .. + })) = tcx.hir().get_if_local(method.def_id).as_ref() + { + let sm = tcx.sess.source_map(); + Some(( + ( + format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }), + sm.span_through_char(sig.span, '(').shrink_to_hi(), + ), + ( + format!("{} Self: Sized", generics.add_where_or_trailing_comma()), + generics.tail_span_for_predicate_suggestion(), + ), + )) + } else { + None + }; + return Some(MethodViolationCode::StaticMethod(sugg)); } - for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { + for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) { if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { - return Some(MethodViolationCode::ReferencesSelfInput(i)); + let span = if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + .. + })) = tcx.hir().get_if_local(method.def_id).as_ref() + { + Some(sig.decl.inputs[i].span) + } else { + None + }; + return Some(MethodViolationCode::ReferencesSelfInput(span)); } } if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { @@ -456,7 +459,16 @@ fn virtual_call_violation_for_method<'tcx>( // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. if receiver_ty != tcx.types.self_param { if !receiver_is_dispatchable(tcx, method, receiver_ty) { - return Some(MethodViolationCode::UndispatchableReceiver); + let span = if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, _), + .. + })) = tcx.hir().get_if_local(method.def_id).as_ref() + { + Some(sig.decl.inputs[0].span) + } else { + None + }; + return Some(MethodViolationCode::UndispatchableReceiver(span)); } else { // Do sanity check to make sure the receiver actually has the layout of a pointer. @@ -719,7 +731,7 @@ fn receiver_is_dispatchable<'tcx>( }) } -fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( +fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, value: T, @@ -829,15 +841,13 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // // This shouldn't really matter though as we can't really use any // constants which are not considered const evaluatable. - use rustc_middle::thir::abstract_const::Node; + use rustc_middle::ty::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { - match node.root(self.tcx) { - Node::Leaf(leaf) => self.visit_const(leaf), - Node::Cast(_, _, ty) => self.visit_ty(ty), - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) { + Node::Leaf(leaf) => self.visit_const(leaf), + Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE } }) } else { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 82c54291a5d5e..b3e7fbb357828 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -28,10 +28,10 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; -use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::select::OverflowError; -use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable}; use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -252,22 +252,10 @@ fn project_and_unify_type<'cx, 'tcx>( Err(InProgress) => return ProjectAndUnifyResult::Recursive, }; debug!(?normalized, ?obligations, "project_and_unify_type result"); - let actual = obligation.predicate.term; - // HACK: lazy TAIT would regress src/test/ui/impl-trait/nested-return-type2.rs, so we add - // a back-compat hack hat converts the RPITs into inference vars, just like they were before - // lazy TAIT. - // This does not affect TAITs in general, as tested in the nested-return-type-tait* tests. - let InferOk { value: actual, obligations: new } = - selcx.infcx().replace_opaque_types_with_inference_vars( - actual, - obligation.cause.body_id, - obligation.cause.span, - ObligationCauseCode::MiscObligation, - obligation.param_env, - ); - obligations.extend(new); - - match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) { + match infcx + .at(&obligation.cause, obligation.param_env) + .eq(normalized, obligation.predicate.term) + { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); ProjectAndUnifyResult::Holds(obligations) @@ -372,7 +360,7 @@ where result } -pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool { +pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool { match reveal { Reveal::UserFacing => value .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 25cc6e9f9f2f1..aad3c37f84e5a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -1,73 +1,7 @@ -use crate::infer::at::At; -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferOk; - -use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, Ty, TyCtxt}; pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; -pub trait AtExt<'tcx> { - fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>>; -} - -impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { - /// Given a type `ty` of some value being dropped, computes a set - /// of "kinds" (types, regions) that must be outlive the execution - /// of the destructor. These basically correspond to data that the - /// destructor might access. This is used during regionck to - /// impose "outlives" constraints on any lifetimes referenced - /// within. - /// - /// The rules here are given by the "dropck" RFCs, notably [#1238] - /// and [#1327]. This is a fixed-point computation, where we - /// explore all the data that will be dropped (transitively) when - /// a value of type `ty` is dropped. For each type T that will be - /// dropped and which has a destructor, we must assume that all - /// the types/regions of T are live during the destructor, unless - /// they are marked with a special attribute (`#[may_dangle]`). - /// - /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md - /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md - fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> { - debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,); - - // Quick check: there are a number of cases that we know do not require - // any destructor. - let tcx = self.infcx.tcx; - if trivial_dropck_outlives(tcx, ty) { - return InferOk { value: vec![], obligations: vec![] }; - } - - let mut orig_values = OriginalQueryValues::default(); - let c_ty = self.infcx.canonicalize_query(self.param_env.and(ty), &mut orig_values); - let span = self.cause.span; - debug!("c_ty = {:?}", c_ty); - if let Ok(result) = tcx.dropck_outlives(c_ty) - && result.is_proven() - && let Ok(InferOk { value, obligations }) = - self.infcx.instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - result, - ) - { - let ty = self.infcx.resolve_vars_if_possible(ty); - let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); - return InferOk { value: kinds, obligations }; - } - - // Errors and ambiguity in dropck occur in two cases: - // - unresolved inference variables at the end of typeck - // - non well-formed types where projections cannot be resolved - // Either of these should have created an error before. - tcx.sess.delay_span_bug(span, "dtorck encountered internal error"); - - InferOk { value: vec![], obligations: vec![] } - } -} - /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to /// outlive. This is similar but not *quite* the same as the @@ -79,6 +13,8 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// /// Note also that `needs_drop` requires a "global" type (i.e., one /// with erased regions), but this function does not. +/// +// FIXME(@lcnr): remove this module and move this function somewhere else. pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { // None of these types have a destructor and hence they do not @@ -105,7 +41,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty), // (T1..Tn) and closures have same properties as T1..Tn -- - // check if *any* of those are trivial. + // check if *all* of them are trivial. ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), ty::Closure(_, ref substs) => { trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty()) 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 db45ee3fed7db..32669e23db96b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -84,7 +84,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. - self.tcx.at(obligation.cause.span(self.tcx)).evaluate_obligation(c_pred) + self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) } // Helper function that canonicalizes and runs the query. If an diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b80a27eb07d06..449d7a7b47b1f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -12,8 +12,9 @@ use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::mir; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; use std::ops::ControlFlow; @@ -108,7 +109,7 @@ struct MaxEscapingBoundVarVisitor { } impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { - fn visit_binder<T: TypeFoldable<'tcx>>( + fn visit_binder<T: TypeVisitable<'tcx>>( &mut self, t: &ty::Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { @@ -162,15 +163,13 @@ struct QueryNormalizer<'cx, 'tcx> { universes: Vec<Option<ty::UniverseIndex>>, } -impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { +impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { type Error = NoSolution; fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { self.infcx.tcx } -} -impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { fn try_fold_binder<T: TypeFoldable<'tcx>>( &mut self, t: ty::Binder<'tcx, T>, @@ -255,7 +254,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - return Err(NoSolution); + bug!("unexpected ambiguity: {:?} {:?}", c_data, result); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -294,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - return Err(NoSolution); + bug!("unexpected ambiguity: {:?} {:?}", c_data, result); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( 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 605c9ace5ed06..c9d46b2810ddb 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 @@ -95,7 +95,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx.tcx, region_obligations .iter() - .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) + .map(|r_o| (r_o.sup_type, r_o.sub_region)) .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)), ®ion_constraint_data, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 46d6e973d4cf9..2a3319f0f26fb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -3,7 +3,7 @@ use crate::traits::query::Fallible; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ImpliedOutlivesBounds<'tcx> { pub ty: Ty<'tcx>, } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 82f147f8143d3..b63382429d0aa 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -3,7 +3,7 @@ use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutli use crate::traits::query::Fallible; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct DropckOutlives<'tcx> { dropped_ty: Ty<'tcx>, } 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 cfd50c1afb9e2..6e8581128dd8e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -12,7 +12,7 @@ use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; use rustc_target::spec::abi::Abi; use crate::traits; @@ -108,7 +108,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } }; debug!(?cause, "evaluate_stack: pushing cause"); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 5942bb79d69e8..da8ca6e574916 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -12,7 +12,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use rustc_middle::ty::{ToPolyTraitRef, ToPredicate}; use rustc_span::def_id::DefId; @@ -555,7 +555,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); let bound = - EarlyBinder(bound.0.kind().skip_binder()).subst(tcx, assoc_ty_substs); + bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs); tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars)) }; let normalized_bound = normalize_with_depth_to( @@ -683,7 +683,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // FIXME: Chalk - if !self.tcx().sess.opts.debugging_opts.chalk { + if !self.tcx().sess.opts.unstable_opts.chalk { nested.push(Obligation::new( obligation.cause.clone(), obligation.param_env, @@ -813,7 +813,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - ObjectCastObligation(target), + ObjectCastObligation(source, target), ); let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth( @@ -910,7 +910,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - ObjectCastObligation(target), + ObjectCastObligation(source, target), ); let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth( @@ -931,7 +931,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - ObjectCastObligation(target), + ObjectCastObligation(source, target), ); let predicate_to_obligation = |predicate| { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 297fbfa1c3276..fa2d2c751d929 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -24,7 +24,7 @@ use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; @@ -32,14 +32,14 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::thir::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; -use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_span::symbol::sym; use std::cell::{Cell, RefCell}; @@ -52,7 +52,7 @@ pub use rustc_middle::traits::select::*; mod candidate_assembly; mod confirmation; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum IntercrateAmbiguityCause { DownstreamCrate { trait_desc: String, self_desc: Option<String> }, UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> }, @@ -128,7 +128,7 @@ pub struct SelectionContext<'cx, 'tcx> { /// We don't do his until we detect a coherence error because it can /// lead to false overflow results (#47139) and because always /// computing it may negatively impact performance. - intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>, + intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause>>, /// The mode that trait queries run in, which informs our error handling /// policy. In essence, canonicalized queries need their errors propagated @@ -254,14 +254,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { assert!(self.intercrate); assert!(self.intercrate_ambiguity_causes.is_none()); - self.intercrate_ambiguity_causes = Some(vec![]); + self.intercrate_ambiguity_causes = Some(FxIndexSet::default()); debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); } /// Gets the intercrate ambiguity causes collected since tracking /// was enabled and disables tracking at the same time. If /// tracking is not enabled, just returns an empty vector. - pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> { + pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> { assert!(self.intercrate); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -394,6 +394,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(_) => return Ok(EvaluatedToErr), } + if self.infcx.opaque_types_added_in_snapshot(snapshot) { + return Ok(result.max(EvaluatedToOkModuloOpaqueTypes)); + } + match self.infcx.region_constraints_added_in_snapshot(snapshot) { None => Ok(result), Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), @@ -488,20 +492,93 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::WellFormed(arg) => match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - obligation.recursion_depth + 1, - arg, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations) + ty::PredicateKind::WellFormed(arg) => { + // So, there is a bit going on here. First, `WellFormed` predicates + // are coinductive, like trait predicates with auto traits. + // This means that we need to detect if we have recursively + // evaluated `WellFormed(X)`. Otherwise, we would run into + // a "natural" overflow error. + // + // Now, the next question is whether we need to do anything + // special with caching. Considering the following tree: + // - `WF(Foo<T>)` + // - `Bar<T>: Send` + // - `WF(Foo<T>)` + // - `Foo<T>: Trait` + // In this case, the innermost `WF(Foo<T>)` should return + // `EvaluatedToOk`, since it's coinductive. Then if + // `Bar<T>: Send` is resolved to `EvaluatedToOk`, it can be + // inserted into a cache (because without thinking about `WF` + // goals, it isn't in a cycle). If `Foo<T>: Trait` later doesn't + // hold, then `Bar<T>: Send` shouldn't hold. Therefore, we + // *do* need to keep track of coinductive cycles. + + let cache = previous_stack.cache; + let dfn = cache.next_dfn(); + + for stack_arg in previous_stack.cache.wf_args.borrow().iter().rev() { + if stack_arg.0 != arg { + continue; + } + debug!("WellFormed({:?}) on stack", arg); + if let Some(stack) = previous_stack.head { + // Okay, let's imagine we have two different stacks: + // `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait` + // `WF(T) -> T: NonAutoTrait -> WF(T)` + // Because of this, we need to check that all + // predicates between the WF goals are coinductive. + // Otherwise, we can say that `T: NonAutoTrait` is + // true. + // Let's imagine we have a predicate stack like + // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto + // depth ^1 ^2 ^3 + // and the current predicate is `WF(T)`. `wf_args` + // would contain `(T, 1)`. We want to check all + // trait predicates greater than `1`. The previous + // stack would be `T: Auto`. + let cycle = stack.iter().take_while(|s| s.depth > stack_arg.1); + let tcx = self.tcx(); + let cycle = + cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx)); + if self.coinductive_match(cycle) { + stack.update_reached_depth(stack_arg.1); + return Ok(EvaluatedToOk); + } else { + return Ok(EvaluatedToRecur); + } + } + return Ok(EvaluatedToOk); } - None => Ok(EvaluatedToAmbig), - }, + + match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + obligation.recursion_depth + 1, + arg, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + + cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); + let result = + self.evaluate_predicates_recursively(previous_stack, obligations); + cache.wf_args.borrow_mut().pop(); + + let result = result?; + + if !result.must_apply_modulo_regions() { + cache.on_failure(dfn); + } + + cache.on_completion(dfn); + + Ok(result) + } + None => Ok(EvaluatedToAmbig), + } + } ty::PredicateKind::TypeOutlives(pred) => { // A global type with no late-bound regions can only @@ -665,7 +742,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr), (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { span_bug!( - obligation.cause.span(self.tcx()), + obligation.cause.span(), "ConstEquate: const_eval_resolve returned an unexpected error" ) } @@ -718,6 +795,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?fresh_trait_pred); + // If a trait predicate is in the (local or global) evaluation cache, + // then we know it holds without cycles. if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { debug!(?result, "CACHE HIT"); return Ok(result); @@ -881,7 +960,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); debug!(?cause, "evaluate_stack: pushing cause"); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); } } } @@ -921,7 +1000,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// - it also appears in the backtrace at some position `X`, /// - all the predicates at positions `X..` between `X` and the top are /// also defaulted traits. - pub fn coinductive_match<I>(&mut self, mut cycle: I) -> bool + pub(crate) fn coinductive_match<I>(&mut self, mut cycle: I) -> bool where I: Iterator<Item = ty::Predicate<'tcx>>, { @@ -931,6 +1010,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { let result = match predicate.kind().skip_binder() { ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()), + ty::PredicateKind::WellFormed(_) => true, _ => false, }; debug!(?predicate, ?result, "coinductive_predicate"); @@ -1172,7 +1252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { reservation impl ambiguity on {:?}", def_id ); - intercrate_ambiguity_clauses.push( + intercrate_ambiguity_clauses.insert( IntercrateAmbiguityCause::ReservationImpl { message: value.to_string(), }, @@ -2410,6 +2490,15 @@ struct ProvisionalEvaluationCache<'tcx> { /// all cache values whose DFN is >= 4 -- in this case, that /// means the cached value for `F`. map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>, + + /// The stack of args that we assume to be true because a `WF(arg)` predicate + /// is on the stack above (and because of wellformedness is coinductive). + /// In an "ideal" world, this would share a stack with trait predicates in + /// `TraitObligationStack`. However, trait predicates are *much* hotter than + /// `WellFormed` predicates, and it's very likely that the additional matches + /// will have a perf effect. The value here is the well-formed `GenericArg` + /// and the depth of the trait predicate *above* that well-formed predicate. + wf_args: RefCell<Vec<(ty::GenericArg<'tcx>, usize)>>, } /// A cache value for the provisional cache: contains the depth-first @@ -2423,7 +2512,7 @@ struct ProvisionalEvaluation { impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { fn default() -> Self { - Self { dfn: Cell::new(0), map: Default::default() } + Self { dfn: Cell::new(0), map: Default::default(), wf_args: Default::default() } } } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 95f1e224a4c7f..2c4a453aefc34 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -15,10 +15,9 @@ use specialization_graph::GraphExt; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, EmissionGuarantee}; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, ImplSubject, TyCtxt}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; @@ -34,7 +33,7 @@ pub struct OverlapError { pub with_impl: DefId, pub trait_desc: String, pub self_desc: Option<String>, - pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, + pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>, pub involves_placeholder: bool, } @@ -341,10 +340,7 @@ fn report_negative_positive_conflict( positive_impl_def_id: DefId, sg: &mut specialization_graph::Graph, ) { - let impl_span = tcx - .sess - .source_map() - .guess_head_span(tcx.span_of_impl(local_impl_def_id.to_def_id()).unwrap()); + let impl_span = tcx.def_span(local_impl_def_id); let mut err = struct_span_err!( tcx.sess, @@ -357,10 +353,7 @@ fn report_negative_positive_conflict( match tcx.span_of_impl(negative_impl_def_id) { Ok(span) => { - err.span_label( - tcx.sess.source_map().guess_head_span(span), - "negative implementation here".to_string(), - ); + err.span_label(span, "negative implementation here"); } Err(cname) => { err.note(&format!("negative implementation in crate `{}`", cname)); @@ -369,10 +362,7 @@ fn report_negative_positive_conflict( match tcx.span_of_impl(positive_impl_def_id) { Ok(span) => { - err.span_label( - tcx.sess.source_map().guess_head_span(span), - "positive implementation here".to_string(), - ); + err.span_label(span, "positive implementation here"); } Err(cname) => { err.note(&format!("positive implementation in crate `{}`", cname)); @@ -389,8 +379,7 @@ fn report_conflicting_impls( used_to_be_allowed: Option<FutureCompatOverlapErrorKind>, sg: &mut specialization_graph::Graph, ) { - let impl_span = - tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id.to_def_id()).unwrap()); + let impl_span = tcx.def_span(impl_def_id); // Work to be done after we've built the DiagnosticBuilder. We have to define it // now because the struct_lint methods don't return back the DiagnosticBuilder @@ -417,10 +406,7 @@ fn report_conflicting_impls( let mut err = err.build(&msg); match tcx.span_of_impl(overlap.with_impl) { Ok(span) => { - err.span_label( - tcx.sess.source_map().guess_head_span(span), - "first implementation here".to_string(), - ); + err.span_label(span, "first implementation here"); err.span_label( impl_span, @@ -452,7 +438,7 @@ fn report_conflicting_impls( match used_to_be_allowed { None => { let reported = if overlap.with_impl.is_local() - || !tcx.orphan_check_crate(()).contains(&impl_def_id) + || tcx.orphan_check_impl(impl_def_id).is_ok() { let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); Some(decorate( 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 930c80e0abb81..fcb73b43fa8a1 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -4,7 +4,7 @@ use crate::traits; use rustc_hir::def_id::DefId; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; pub use rustc_middle::traits::specialization_graph::*; diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index bc2ce31df6d93..6c0b83fbd0304 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; use std::ops::ControlFlow; @@ -26,6 +26,7 @@ pub enum NonStructuralMatchTyKind<'tcx> { Closure, Generator, Projection, + Float, } /// This method traverses the structure of `ty`, trying to find an @@ -53,15 +54,16 @@ pub enum NonStructuralMatchTyKind<'tcx> { /// For more background on why Rust has this requirement, and issues /// that arose when the requirement was not enforced completely, see /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. +/// +/// The floats_allowed flag is used to deny constants in floating point pub fn search_for_structural_match_violation<'tcx>( span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, + floats_allowed: bool, ) -> Option<NonStructuralMatchTy<'tcx>> { - // FIXME: we should instead pass in an `infcx` from the outside. - tcx.infer_ctxt().enter(|infcx| { - ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value() - }) + ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed }) + .break_value() } /// This method returns true if and only if `adt_ty` itself has been marked as @@ -114,27 +116,25 @@ fn type_marked_structural<'tcx>( /// This implements the traversal over the structure of a given type to try to /// find instances of ADTs (specifically structs or enums) that do not implement /// the structural-match traits (`StructuralPartialEq` and `StructuralEq`). -struct Search<'a, 'tcx> { +struct Search<'tcx> { span: Span, - infcx: InferCtxt<'a, 'tcx>, + tcx: TyCtxt<'tcx>, /// Tracks ADTs previously encountered during search, so that /// we will not recur on them again. seen: FxHashSet<hir::def_id::DefId>, -} -impl<'a, 'tcx> Search<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } + floats_allowed: bool, +} +impl<'tcx> Search<'tcx> { fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { - adt_ty.is_structural_eq_shallow(self.tcx()) + adt_ty.is_structural_eq_shallow(self.tcx) } } -impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { +impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { type BreakTy = NonStructuralMatchTy<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -193,19 +193,30 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { return ControlFlow::CONTINUE; } ty::Array(_, n) - if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => + if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. return ControlFlow::CONTINUE; } - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. return ControlFlow::CONTINUE; } + ty::Float(_) => { + if self.floats_allowed { + return ControlFlow::CONTINUE; + } else { + return ControlFlow::Break(NonStructuralMatchTy { + ty, + kind: NonStructuralMatchTyKind::Float, + }); + } + } + ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. return ty.super_visit_with(self); @@ -214,7 +225,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { bug!("unexpected type during structural-match checking: {:?}", ty); } ty::Error(_) => { - self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); + self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. return ControlFlow::CONTINUE; @@ -244,9 +255,9 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // even though we skip super_visit_with, we must recur on // fields of ADT. - let tcx = self.tcx(); + let tcx = self.tcx; adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| { - let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); + let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); ty.visit_with(self) }) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 3a00c41d90ae6..3170b29ee6973 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -6,7 +6,7 @@ use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable}; use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::{self, util::*}; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 8d666046ad9fd..7b5e1498f2695 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1,11 +1,10 @@ use crate::infer::InferCtxt; -use crate::opaque_types::required_region_bounds; use crate::traits; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_span::Span; use std::iter; @@ -271,7 +270,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } fn normalize(mut self) -> Vec<traits::PredicateObligation<'tcx>> { - let cause = self.cause(traits::MiscObligation); + let cause = self.cause(traits::WellFormed(None)); let infcx = &mut self.infcx; let param_env = self.param_env; let mut obligations = Vec::with_capacity(self.out.len()); @@ -385,7 +384,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); let tcx = self.tcx(); - let cause = self.cause(traits::MiscObligation); + let cause = self.cause(traits::WellFormed(None)); let param_env = self.param_env; let depth = self.recursion_depth; @@ -445,7 +444,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) .to_predicate(self.tcx()); - let cause = self.cause(traits::MiscObligation); + let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( cause, self.recursion_depth, @@ -457,7 +456,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let resolved = self.infcx.shallow_resolve(infer); // the `InferConst` changed, meaning that we made progress. if resolved != infer { - let cause = self.cause(traits::MiscObligation); + let cause = self.cause(traits::WellFormed(None)); let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(resolved), @@ -648,7 +647,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; if !defer_to_coercion { - let cause = self.cause(traits::MiscObligation); + let cause = self.cause(traits::WellFormed(None)); let component_traits = data.auto_traits().chain(data.principal_def_id()); let tcx = self.tcx(); self.out.extend(component_traits.map(|did| { @@ -679,7 +678,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let ty = self.infcx.shallow_resolve(ty); if let ty::Infer(ty::TyVar(_)) = ty.kind() { // Not yet resolved, but we've made progress. - let cause = self.cause(traits::MiscObligation); + let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( cause, self.recursion_depth, @@ -810,3 +809,63 @@ pub fn object_region_bounds<'tcx>( required_region_bounds(tcx, open_ty, predicates) } + +/// Given a set of predicates that apply to an object type, returns +/// the region bounds that the (erased) `Self` type must +/// outlive. Precisely *because* the `Self` type is erased, the +/// parameter `erased_self_ty` must be supplied to indicate what type +/// has been used to represent `Self` in the predicates +/// themselves. This should really be a unique type; `FreshTy(0)` is a +/// popular choice. +/// +/// N.B., in some cases, particularly around higher-ranked bounds, +/// this function returns a kind of conservative approximation. +/// That is, all regions returned by this function are definitely +/// required, but there may be other region bounds that are not +/// returned, as well as requirements like `for<'a> T: 'a`. +/// +/// Requires that trait definitions have been processed so that we can +/// elaborate predicates and walk supertraits. +#[instrument(skip(tcx, predicates), level = "debug")] +pub(crate) fn required_region_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + erased_self_ty: Ty<'tcx>, + predicates: impl Iterator<Item = ty::Predicate<'tcx>>, +) -> Vec<ty::Region<'tcx>> { + assert!(!erased_self_ty.has_escaping_bound_vars()); + + traits::elaborate_predicates(tcx, predicates) + .filter_map(|obligation| { + debug!(?obligation); + match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Trait(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == &erased_self_ty && !r.has_escaping_bound_vars() { + Some(*r) + } else { + None + } + } + } + }) + .collect() +} diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 67f878df31cb5..951554c77fbb5 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -15,6 +15,6 @@ rustc_span = { path = "../rustc_span" } chalk-ir = "0.80.0" chalk-engine = "0.80.0" chalk-solve = "0.80.0" -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e9f05ce9e0688..c7c604e14e3ee 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -35,7 +35,8 @@ use rustc_ast::ast; use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ - self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor, + self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_span::def_id::DefId; @@ -106,8 +107,16 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' ty::PredicateKind::Projection(predicate) => chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), ), - ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::ObjectSafe(..) + ty::PredicateKind::WellFormed(arg) => match arg.unpack() { + ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed( + chalk_ir::WellFormed::Ty(ty.lower_into(interner)), + ), + // FIXME(chalk): we need to change `WellFormed` in Chalk to take a `GenericArg` + _ => chalk_ir::DomainGoal::WellFormed(chalk_ir::WellFormed::Ty( + interner.tcx.types.unit.lower_into(interner), + )), + }, + ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -888,7 +897,7 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>( + fn visit_binder<T: TypeVisitable<'tcx>>( &mut self, t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index 59cf37fee9c43..db7ea4253e36c 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -14,7 +14,7 @@ use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; use rustc_middle::traits::ChalkRustInterner; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_infer::infer::canonical::{ Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 965324113d526..c7cac8fca899b 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; @@ -44,9 +44,10 @@ fn compute_implied_outlives_bounds<'tcx>( // Sometimes when we ask what it takes for T: WF, we get back that // U: WF is required; in that case, we push U onto this stack and - // process it next. Currently (at least) these resulting - // predicates are always guaranteed to be a subset of the original - // type, so we need not fear non-termination. + // process it next. Because the resulting predicates aren't always + // guaranteed to be a subset of the original type, so we need to store the + // WF args we've computed in a set. + let mut checked_wf_args = rustc_data_structures::stable_set::FxHashSet::default(); let mut wf_args = vec![ty.into()]; let mut implied_bounds = vec![]; @@ -54,6 +55,10 @@ fn compute_implied_outlives_bounds<'tcx>( let mut fulfill_cx = FulfillmentContext::new(); while let Some(arg) = wf_args.pop() { + if !checked_wf_args.insert(arg) { + continue; + } + // Compute the obligations for `arg` to be well-formed. If `arg` is // an unresolved inference variable, just substituted an empty set // -- because the return type here is going to be things we *add* diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index d03d675bfd231..caad2ed4274f8 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -15,3 +15,4 @@ rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } +rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs new file mode 100644 index 0000000000000..7c2f4db94ff72 --- /dev/null +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -0,0 +1,469 @@ +use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::LocalDefId; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::ty::abstract_const::{CastKind, Node, NodeId}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_middle::{mir, thir}; +use rustc_span::Span; +use rustc_target::abi::VariantIdx; + +use std::iter; + +/// Destructures array, ADT or tuple constants into the constants +/// of their fields. +pub(crate) fn destructure_const<'tcx>( + tcx: TyCtxt<'tcx>, + const_: ty::Const<'tcx>, +) -> ty::DestructuredConst<'tcx> { + let ty::ConstKind::Value(valtree) = const_.kind() else { + bug!("cannot destructure constant {:?}", const_) + }; + + let branches = match valtree { + ty::ValTree::Branch(b) => b, + _ => bug!("cannot destructure constant {:?}", const_), + }; + + let (fields, variant) = match const_.ty().kind() { + ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { + // construct the consts for the elements of the array/slice + let field_consts = branches + .iter() + .map(|b| tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty })) + .collect::<Vec<_>>(); + debug!(?field_consts); + + (field_consts, None) + } + ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"), + ty::Adt(def, substs) => { + let (variant_idx, branches) = if def.is_enum() { + let (head, rest) = branches.split_first().unwrap(); + (VariantIdx::from_u32(head.unwrap_leaf().try_to_u32().unwrap()), rest) + } else { + (VariantIdx::from_u32(0), branches) + }; + let fields = &def.variant(variant_idx).fields; + let mut field_consts = Vec::with_capacity(fields.len()); + + for (field, field_valtree) in iter::zip(fields, branches) { + let field_ty = field.ty(tcx, substs); + let field_const = tcx.mk_const(ty::ConstS { + kind: ty::ConstKind::Value(*field_valtree), + ty: field_ty, + }); + field_consts.push(field_const); + } + debug!(?field_consts); + + (field_consts, Some(variant_idx)) + } + ty::Tuple(elem_tys) => { + let fields = iter::zip(*elem_tys, branches) + .map(|(elem_ty, elem_valtree)| { + tcx.mk_const(ty::ConstS { + kind: ty::ConstKind::Value(*elem_valtree), + ty: elem_ty, + }) + }) + .collect::<Vec<_>>(); + + (fields, None) + } + _ => bug!("cannot destructure constant {:?}", const_), + }; + + let fields = tcx.arena.alloc_from_iter(fields.into_iter()); + + ty::DestructuredConst { variant, fields } +} + +pub struct AbstractConstBuilder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body_id: thir::ExprId, + body: &'a thir::Thir<'tcx>, + /// The current WIP node tree. + nodes: IndexVec<NodeId, Node<'tcx>>, +} + +impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn root_span(&self) -> Span { + self.body.exprs[self.body_id].span + } + + fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> { + let reported = self + .tcx + .sess + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span, msg) + .help("consider moving this anonymous constant into a `const` function") + .emit(); + + Err(reported) + } + fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> { + let reported = self + .tcx + .sess + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span, msg) + .help("consider moving this anonymous constant into a `const` function") + .note("this operation may be supported in the future") + .emit(); + + Err(reported) + } + + #[instrument(skip(tcx, body, body_id), level = "debug")] + pub fn new( + tcx: TyCtxt<'tcx>, + (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), + ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorGuaranteed> { + let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() }; + + struct IsThirPolymorphic<'a, 'tcx> { + is_poly: bool, + thir: &'a thir::Thir<'tcx>, + } + + use crate::rustc_middle::thir::visit::Visitor; + use thir::visit; + + impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { + fn expr_is_poly(&mut self, expr: &thir::Expr<'tcx>) -> bool { + if expr.ty.has_param_types_or_consts() { + return true; + } + + match expr.kind { + thir::ExprKind::NamedConst { substs, .. } => substs.has_param_types_or_consts(), + thir::ExprKind::ConstParam { .. } => true, + thir::ExprKind::Repeat { value, count } => { + self.visit_expr(&self.thir()[value]); + count.has_param_types_or_consts() + } + _ => false, + } + } + + fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool { + if pat.ty.has_param_types_or_consts() { + return true; + } + + match pat.kind.as_ref() { + thir::PatKind::Constant { value } => value.has_param_types_or_consts(), + thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => { + lo.has_param_types_or_consts() || hi.has_param_types_or_consts() + } + _ => false, + } + } + } + + impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { + fn thir(&self) -> &'a thir::Thir<'tcx> { + &self.thir + } + + #[instrument(skip(self), level = "debug")] + fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { + self.is_poly |= self.expr_is_poly(expr); + if !self.is_poly { + visit::walk_expr(self, expr) + } + } + + #[instrument(skip(self), level = "debug")] + fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { + self.is_poly |= self.pat_is_poly(pat); + if !self.is_poly { + visit::walk_pat(self, pat); + } + } + } + + let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body }; + visit::walk_expr(&mut is_poly_vis, &body[body_id]); + debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); + if !is_poly_vis.is_poly { + return Ok(None); + } + + Ok(Some(builder)) + } + + /// We do not allow all binary operations in abstract consts, so filter disallowed ones. + fn check_binop(op: mir::BinOp) -> bool { + use mir::BinOp::*; + match op { + Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le + | Ne | Ge | Gt => true, + Offset => false, + } + } + + /// While we currently allow all unary operations, we still want to explicitly guard against + /// future changes here. + fn check_unop(op: mir::UnOp) -> bool { + use mir::UnOp::*; + match op { + Not | Neg => true, + } + } + + /// Builds the abstract const by walking the thir and bailing out when + /// encountering an unsupported operation. + pub fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorGuaranteed> { + debug!("AbstractConstBuilder::build: body={:?}", &*self.body); + self.recurse_build(self.body_id)?; + + for n in self.nodes.iter() { + if let Node::Leaf(ct) = n { + if let ty::ConstKind::Unevaluated(ct) = ct.kind() { + // `AbstractConst`s should not contain any promoteds as they require references which + // are not allowed. + assert_eq!(ct.promoted, None); + assert_eq!(ct, self.tcx.erase_regions(ct)); + } + } + } + + Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) + } + + fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorGuaranteed> { + use thir::ExprKind; + let node = &self.body.exprs[node]; + Ok(match &node.kind { + // I dont know if handling of these 3 is correct + &ExprKind::Scope { value, .. } => self.recurse_build(value)?, + &ExprKind::PlaceTypeAscription { source, .. } + | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + &ExprKind::Literal { lit, neg} => { + let sp = node.span; + let constant = + match self.tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { + Ok(c) => c, + Err(LitToConstError::Reported) => { + self.tcx.const_error(node.ty) + } + Err(LitToConstError::TypeError) => { + bug!("encountered type error in lit_to_const") + } + }; + + self.nodes.push(Node::Leaf(constant)) + } + &ExprKind::NonHirLiteral { lit , user_ty: _} => { + let val = ty::ValTree::from_scalar_int(lit); + self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty))) + } + &ExprKind::ZstLiteral { user_ty: _ } => { + let val = ty::ValTree::zst(); + self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty))) + } + &ExprKind::NamedConst { def_id, substs, user_ty: _ } => { + let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs); + + let constant = self.tcx.mk_const(ty::ConstS { + kind: ty::ConstKind::Unevaluated(uneval), + ty: node.ty, + }); + + self.nodes.push(Node::Leaf(constant)) + } + + ExprKind::ConstParam {param, ..} => { + let const_param = self.tcx.mk_const(ty::ConstS { + kind: ty::ConstKind::Param(*param), + ty: node.ty, + }); + self.nodes.push(Node::Leaf(const_param)) + } + + ExprKind::Call { fun, args, .. } => { + let fun = self.recurse_build(*fun)?; + + let mut new_args = Vec::<NodeId>::with_capacity(args.len()); + for &id in args.iter() { + new_args.push(self.recurse_build(id)?); + } + let new_args = self.tcx.arena.alloc_slice(&new_args); + self.nodes.push(Node::FunctionCall(fun, new_args)) + } + &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { + let lhs = self.recurse_build(lhs)?; + let rhs = self.recurse_build(rhs)?; + self.nodes.push(Node::Binop(op, lhs, rhs)) + } + &ExprKind::Unary { op, arg } if Self::check_unop(op) => { + let arg = self.recurse_build(arg)?; + self.nodes.push(Node::UnaryOp(op, arg)) + } + // This is necessary so that the following compiles: + // + // ``` + // fn foo<const N: usize>(a: [(); N + 1]) { + // bar::<{ N + 1 }>(); + // } + // ``` + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { + self.recurse_build(*e)? + } + // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a + // "coercion cast" i.e. using a coercion or is a no-op. + // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) + &ExprKind::Use { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(CastKind::Use, arg, node.ty)) + } + &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(CastKind::As, arg, node.ty)) + } + ExprKind::Borrow{ arg, ..} => { + let arg_node = &self.body.exprs[*arg]; + + // Skip reborrows for now until we allow Deref/Borrow/AddressOf + // expressions. + // FIXME(generic_const_exprs): Verify/explain why this is sound + if let ExprKind::Deref { arg } = arg_node.kind { + self.recurse_build(arg)? + } else { + self.maybe_supported_error( + node.span, + "borrowing is not supported in generic constants", + )? + } + } + // FIXME(generic_const_exprs): We may want to support these. + ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error( + node.span, + "dereferencing or taking the address is not supported in generic constants", + )?, + ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( + node.span, + "array construction is not supported in generic constants", + )?, + ExprKind::Block { .. } => self.maybe_supported_error( + node.span, + "blocks are not supported in generic constant", + )?, + ExprKind::NeverToAny { .. } => self.maybe_supported_error( + node.span, + "converting nevers to any is not supported in generic constant", + )?, + ExprKind::Tuple { .. } => self.maybe_supported_error( + node.span, + "tuple construction is not supported in generic constants", + )?, + ExprKind::Index { .. } => self.maybe_supported_error( + node.span, + "indexing is not supported in generic constant", + )?, + ExprKind::Field { .. } => self.maybe_supported_error( + node.span, + "field access is not supported in generic constant", + )?, + ExprKind::ConstBlock { .. } => self.maybe_supported_error( + node.span, + "const blocks are not supported in generic constant", + )?, + ExprKind::Adt(_) => self.maybe_supported_error( + node.span, + "struct/enum construction is not supported in generic constants", + )?, + // dont know if this is correct + ExprKind::Pointer { .. } => + self.error(node.span, "pointer casts are not allowed in generic constants")?, + ExprKind::Yield { .. } => + self.error(node.span, "generator control flow is not allowed in generic constants")?, + ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self + .error( + node.span, + "loops and loop control flow are not supported in generic constants", + )?, + ExprKind::Box { .. } => + self.error(node.span, "allocations are not allowed in generic constants")?, + + ExprKind::Unary { .. } => unreachable!(), + // we handle valid unary/binary ops above + ExprKind::Binary { .. } => + self.error(node.span, "unsupported binary operation in generic constants")?, + ExprKind::LogicalOp { .. } => + self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, + ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { + self.error(node.span, "assignment is not supported in generic constants")? + } + ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( + node.span, + "closures and function keywords are not supported in generic constants", + )?, + // let expressions imply control flow + ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => + self.error(node.span, "control flow is not supported in generic constants")?, + ExprKind::InlineAsm { .. } => { + self.error(node.span, "assembly is not supported in generic constants")? + } + + // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen + ExprKind::VarRef { .. } + | ExprKind::UpvarRef { .. } + | ExprKind::StaticRef { .. } + | ExprKind::ThreadLocalRef(_) => { + self.error(node.span, "unsupported operation in generic constant")? + } + }) + } +} + +/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. +pub fn thir_abstract_const<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam<LocalDefId>, +) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> { + if tcx.features().generic_const_exprs { + match tcx.def_kind(def.did) { + // FIXME(generic_const_exprs): We currently only do this for anonymous constants, + // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether + // we want to look into them or treat them as opaque projections. + // + // Right now we do neither of that and simply always fail to unify them. + DefKind::AnonConst | DefKind::InlineConst => (), + _ => return Ok(None), + } + + let body = tcx.thir_body(def)?; + + AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))? + .map(AbstractConstBuilder::build) + .transpose() + } else { + Ok(None) + } +} + +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 { + thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + thir_abstract_const( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + ) + }, + ..*providers + }; +} diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 552db5406df8d..5e58f2379827e 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{ - self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor, + self, Binder, Instance, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_span::{sym, DUMMY_SP}; use rustc_trait_selection::traits; @@ -56,7 +56,7 @@ impl<'tcx> BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { type BreakTy = (); - fn visit_binder<T: TypeFoldable<'tcx>>( + fn visit_binder<T: TypeVisitable<'tcx>>( &mut self, t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { @@ -332,12 +332,12 @@ fn resolve_associated_item<'tcx>( }), traits::ImplSource::Closure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); - Some(Instance::resolve_closure( + Instance::resolve_closure( tcx, closure_data.closure_def_id, closure_data.substs, trait_closure_kind, - )) + ) } traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 484967bbef8ce..09f5c2a11aaa8 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -7,6 +7,8 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(control_flow_enum)] #![feature(let_else)] +#![feature(never_type)] +#![feature(box_patterns)] #![recursion_limit = "256"] #[macro_use] @@ -18,6 +20,7 @@ use rustc_middle::ty::query::Providers; mod assoc; mod common_traits; +mod consts; pub mod instance; mod needs_drop; pub mod representability; @@ -26,6 +29,7 @@ mod ty; pub fn provide(providers: &mut Providers) { assoc::provide(providers); common_traits::provide(providers); + consts::provide(providers); needs_drop::provide(providers); ty::provide(providers); instance::provide(providers); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 38ae6a25b1806..d542a9b599724 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -126,7 +126,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so outside of type inference you can be // sure that this will succeed without errors anyway. - if tcx.sess.opts.debugging_opts.chalk { + if tcx.sess.opts.unstable_opts.chalk { let environment = well_formed_types_in_env(tcx, def_id); predicates.extend(environment); } @@ -211,7 +211,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id) }); let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); - traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) + traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) } /// Elaborate the environment. diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index b8066f2e5d891..5aa3cf017fa68 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -12,4 +12,4 @@ rustc_index = { path = "../rustc_index" } rustc_serialize = { path = "../rustc_serialize" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index cb1602816ae5e..fd6376ef6ee9d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(fmt_helpers_for_derive)] #![feature(min_specialization)] #![feature(rustc_attrs)] @@ -203,14 +204,6 @@ bitflags! { | TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits - // The `evaluate_obligation` query does not return further - // obligations. If it evaluates an obligation with an opaque - // type, that opaque type may get compared to another type, - // constraining it. We would lose this information. - // FIXME: differentiate between crate-local opaque types - // and opaque types from other crates, as only opaque types - // from the local crate can possibly be a local name - | TypeFlags::HAS_TY_OPAQUE.bits // We consider 'freshened' types and constants // to depend on a particular fn. // The freshening process throws away information, @@ -598,6 +591,7 @@ impl UnifyKey for FloatVid { } #[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)] +#[rustc_pass_by_value] pub enum Variance { Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 5cd2901324a2e..74737e30bb4d3 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -554,137 +554,37 @@ impl<I: Interner> hash::Hash for TyKind<I> { // This is manually implemented because a derive would require `I: Debug` impl<I: Interner> fmt::Debug for TyKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match (&*self,) { - (&Bool,) => fmt::Formatter::write_str(f, "Bool"), - (&Char,) => fmt::Formatter::write_str(f, "Char"), - (&Int(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Int"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Uint(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Uint"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Float(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Float"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Adt(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Adt"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Foreign(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Foreign"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Str,) => fmt::Formatter::write_str(f, "Str"), - (&Array(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Array"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Slice(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Slice"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&RawPtr(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "RawPtr"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Ref(ref __self_0, ref __self_1, ref __self_2),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Ref"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&FnDef(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnDef"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&FnPtr(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnPtr"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Dynamic(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Dynamic"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Closure(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Closure"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Generator(ref __self_0, ref __self_1, ref __self_2),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Generator"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&GeneratorWitness(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "GeneratorWitness"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Never,) => fmt::Formatter::write_str(f, "Never"), - (&Tuple(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Tuple"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Projection(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Projection"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Opaque(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Opaque"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Param(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Param"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Bound(ref __self_0, ref __self_1),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Bound"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Placeholder(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Placeholder"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Infer(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Infer"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } - (&Error(ref __self_0),) => { - let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Error"); - let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0); - fmt::DebugTuple::finish(debug_trait_builder) - } + use std::fmt::*; + match self { + Bool => Formatter::write_str(f, "Bool"), + Char => Formatter::write_str(f, "Char"), + Int(f0) => Formatter::debug_tuple_field1_finish(f, "Int", f0), + Uint(f0) => Formatter::debug_tuple_field1_finish(f, "Uint", f0), + Float(f0) => Formatter::debug_tuple_field1_finish(f, "Float", f0), + Adt(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Adt", f0, f1), + Foreign(f0) => Formatter::debug_tuple_field1_finish(f, "Foreign", f0), + Str => Formatter::write_str(f, "Str"), + Array(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Array", f0, f1), + Slice(f0) => Formatter::debug_tuple_field1_finish(f, "Slice", f0), + RawPtr(f0) => Formatter::debug_tuple_field1_finish(f, "RawPtr", f0), + Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2), + FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1), + FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0), + Dynamic(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Dynamic", f0, f1), + Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1), + Generator(f0, f1, f2) => { + Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2) + } + GeneratorWitness(f0) => Formatter::debug_tuple_field1_finish(f, "GeneratorWitness", f0), + Never => Formatter::write_str(f, "Never"), + Tuple(f0) => Formatter::debug_tuple_field1_finish(f, "Tuple", f0), + Projection(f0) => Formatter::debug_tuple_field1_finish(f, "Projection", f0), + Opaque(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Opaque", f0, f1), + Param(f0) => Formatter::debug_tuple_field1_finish(f, "Param", f0), + Bound(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Bound", f0, f1), + Placeholder(f0) => Formatter::debug_tuple_field1_finish(f, "Placeholder", f0), + Infer(f0) => Formatter::debug_tuple_field1_finish(f, "Infer", f0), + TyKind::Error(f0) => Formatter::debug_tuple_field1_finish(f, "Error", f0), } } } diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index c08023ee6a70a..faf52e2695a33 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -20,7 +20,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } -smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index d111008e82c83..c873cf27e42c5 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -164,10 +164,62 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { suggested_name, Applicability::MaybeIncorrect, ); - } else { - err.span_label(span, format!("associated type `{}` not found", assoc_name)); + return err.emit(); } + // If we didn't find a good item in the supertraits (or couldn't get + // the supertraits), like in ItemCtxt, then look more generally from + // all visible traits. If there's one clear winner, just suggest that. + + let visible_traits: Vec<_> = self + .tcx() + .all_traits() + .filter(|trait_def_id| { + let viz = self.tcx().visibility(*trait_def_id); + if let Some(def_id) = self.item_def_id() { + viz.is_accessible_from(def_id, self.tcx()) + } else { + viz.is_visible_locally() + } + }) + .collect(); + + let wider_candidate_names: Vec<_> = visible_traits + .iter() + .flat_map(|trait_def_id| { + self.tcx().associated_items(*trait_def_id).in_definition_order() + }) + .filter_map( + |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, + ) + .collect(); + + if let (Some(suggested_name), true) = ( + find_best_match_for_name(&wider_candidate_names, assoc_name.name, None), + assoc_name.span != DUMMY_SP, + ) { + if let [best_trait] = visible_traits + .iter() + .filter(|trait_def_id| { + self.tcx() + .associated_items(*trait_def_id) + .filter_by_name_unhygienic(suggested_name) + .any(|item| item.kind == ty::AssocKind::Type) + }) + .collect::<Vec<_>>()[..] + { + err.span_label( + assoc_name.span, + format!( + "there is a similarly named associated type `{suggested_name}` in the trait `{}`", + self.tcx().def_path_str(*best_trait) + ), + ); + return err.emit(); + } + } + + err.span_label(span, format!("associated type `{}` not found", assoc_name)); err.emit() } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 60682aa343517..612dc38452188 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -645,7 +645,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.emit(); } else { let mut multispan = MultiSpan::from_span(span); - multispan.push_span_label(span_late, note.to_string()); + multispan.push_span_label(span_late, note); tcx.struct_span_lint_hir( LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].id(), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index eec3b24aec260..9e4da0580522b 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -28,7 +28,7 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ - self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable, + self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable, }; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edition::Edition; @@ -38,7 +38,9 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::astconv_object_safety_violations; -use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::traits::error_reporting::{ + report_object_safety_error, suggestions::NextTypeParamName, +}; use rustc_trait_selection::traits::wf::object_region_bounds; use smallvec::SmallVec; @@ -437,7 +439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // as the rest of the type. As such, we ignore missing // stability attributes. }, - ) + ); } if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) { self.inferred_params.push(ty.span); @@ -548,7 +550,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Const { has_default } => { let ty = tcx.at(self.span).type_of(param.def_id); if !infer_args && has_default { - EarlyBinder(tcx.const_param_default(param.def_id)) + tcx.bound_const_param_default(param.def_id) .subst(tcx, substs.unwrap()) .into() } else { @@ -1957,7 +1959,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if let Some(sp) = tcx.hir().span_if_local(adt_def.did()) { - let sp = tcx.sess.source_map().guess_head_span(sp); err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); } @@ -2448,7 +2449,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let msg = format!("`Self` is of type `{ty}`"); if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) { - let i_sp = tcx.sess.source_map().guess_head_span(i_sp); let mut span: MultiSpan = vec![t_sp].into(); span.push_span_label( i_sp, @@ -2486,7 +2486,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { concrete type's name `{type_name}` instead if you want to \ specify its type parameters" ), - type_name.to_string(), + type_name, Applicability::MaybeIncorrect, ); } @@ -2986,6 +2986,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(r) } + /// Make sure that we are in the condition to suggest the blanket implementation. + fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut DiagnosticBuilder<'_, T>, + ) { + let tcx = self.tcx(); + let parent_id = tcx.hir().get_parent_item(self_ty.hir_id); + if let hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl(hir::Impl { + self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, .. + }), + .. + }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id + { + if !of_trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local()) { + return; + } + let of_trait_span = of_trait_ref.path.span; + // make sure that we are not calling unwrap to abort during the compilation + let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; }; + let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; + // check if the trait has generics, to make a correct suggestion + let param_name = generics.params.next_type_param_name(None); + + let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { + (span, format!(", {}: {}", param_name, impl_trait_name)) + } else { + (generics.span, format!("<{}: {}>", param_name, impl_trait_name)) + }; + diag.multipart_suggestion( + format!("alternatively use a blanket \ + implementation to implement `{of_trait_name}` for \ + all types that also implement `{impl_trait_name}`"), + vec![ + (self_ty.span, param_name), + add_generic_sugg, + ], + Applicability::MaybeIncorrect, + ); + } + } + fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { let tcx = self.tcx(); if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = @@ -3021,9 +3065,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if self_ty.span.edition() >= Edition::Edition2021 { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; - rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg) - .multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable) - .emit(); + let mut diag = + rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg); + diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); + // check if the impl trait that we are considering is a impl of a local trait + self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); + diag.emit(); } else { let msg = "trait objects without an explicit `dyn` are deprecated"; tcx.struct_span_lint_hir( @@ -3031,13 +3078,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty.hir_id, self_ty.span, |lint| { - lint.build(msg) - .multipart_suggestion_verbose( - "use `dyn`", - sugg, - Applicability::MachineApplicable, - ) - .emit(); + let mut diag = lint.build(msg); + diag.multipart_suggestion_verbose( + "use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag); + diag.emit(); }, ); } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index bbdf1dae4a904..7795e65132f50 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -1,10 +1,10 @@ use crate::check::coercion::{AsCoercionSite, CoerceMany}; use crate::check::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_errors::{Applicability, Diagnostic, MultiSpan}; +use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; -use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ @@ -127,7 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(&arm.body), arm_ty, - Some(&mut |err: &mut Diagnostic| { + Some(&mut |err| { let Some(ret) = self.ret_type_span else { return; }; @@ -154,18 +154,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_span.push_span_label( expr.span, "this could be implicitly returned but it is a statement, not a \ - tail expression" - .to_owned(), - ); - ret_span.push_span_label( - ret, - "the `match` arms can conform to this return type".to_owned(), + tail expression", ); + ret_span + .push_span_label(ret, "the `match` arms can conform to this return type"); ret_span.push_span_label( semi_span, "the `match` is a statement because of this semicolon, consider \ - removing it" - .to_owned(), + removing it", ); err.span_note( ret_span, @@ -267,7 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if let ExprKind::Block(block, _) = &then_expr.kind && let Some(expr) = &block.expr { - err.span_label(expr.span, "found here".to_string()); + err.span_label(expr.span, "found here"); } err.note("`if` expressions without `else` evaluate to `()`"); err.help("consider adding an `else` block that evaluates to the expected type"); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 83a8c5ea02191..d14d06237be30 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; @@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // we must check that return type of called functions is WF: - self.register_wf_obligation(output.into(), call_expr.span, traits::MiscObligation); + self.register_wf_obligation(output.into(), call_expr.span, traits::WellFormed(None)); output } @@ -280,15 +280,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_node: &hir::ExprKind<'_>, callee_span: Span, ) { - let hir_id = self.tcx.hir().get_parent_node(hir_id); - let parent_node = self.tcx.hir().get(hir_id); + let hir = self.tcx.hir(); + let parent_hir_id = hir.get_parent_node(hir_id); + let parent_node = hir.get(parent_hir_id); if let ( hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure { fn_decl_span, .. }, .. + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }), + .. }), hir::ExprKind::Block(..), ) = (parent_node, callee_node) { + let fn_decl_span = if hir.body(body).generator_kind + == Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure)) + { + // Actually need to unwrap a few more layers of HIR to get to + // the _real_ closure... + let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id)); + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), + .. + }) = hir.get(async_closure) + { + fn_decl_span + } else { + return; + } + } else { + fn_decl_span + }; + let start = fn_decl_span.shrink_to_lo(); let end = callee_span.shrink_to_hi(); err.multipart_suggestion( diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7d5d6849b3bc4..66dd558249052 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -40,7 +40,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 45c011b78e388..69f3f03cfa97c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1,10 +1,9 @@ -use crate::check::wfcheck::for_item; +use crate::check::intrinsicck::InlineAsmCtxt; use super::coercion::CoerceMany; use super::compare_method::check_type_bounds; use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; use super::*; - use rustc_attr as attr; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; @@ -13,30 +12,29 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemKind, Node, PathSegment}; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; +use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::{ + self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, +}; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_span::symbol::sym; use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_ty_utils::representability::{self, Representability}; use std::iter; use std::ops::ControlFlow; -pub fn check_wf_new(tcx: TyCtxt<'_>) { - let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().par_visit_all_item_likes(&visit); -} - pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { match tcx.sess.target.is_abi_supported(abi) { Some(true) => (), @@ -100,8 +98,7 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars( declared_ret_ty, body.value.hir_id, - DUMMY_SP, - traits::ObligationCauseCode::OpaqueReturnType(None), + decl.output.span(), param_env, )); // If we replaced declared_ret_ty with infer vars, then we must be infering @@ -291,11 +288,9 @@ fn check_panic_info_fn( tcx.sess.span_err(decl.output.span(), "return type should be `!`"); } - let span = tcx.def_span(fn_id); let inputs = fn_sig.inputs(); if inputs.len() != 1 { - let span = tcx.sess.source_map().guess_head_span(span); - tcx.sess.span_err(span, "function should have one argument"); + tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); return; } @@ -348,9 +343,7 @@ fn check_alloc_error_fn( let inputs = fn_sig.inputs(); if inputs.len() != 1 { - let span = tcx.def_span(fn_id); - let span = tcx.sess.source_map().guess_head_span(span); - tcx.sess.span_err(span, "function should have one argument"); + tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); return; } @@ -381,8 +374,9 @@ fn check_alloc_error_fn( } } -fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) { +fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); + let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); @@ -394,8 +388,9 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) { check_packed(tcx, span, def); } -fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) { +fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); + let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); check_transparent(tcx, span, def); @@ -408,11 +403,37 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b let item_type = tcx.type_of(item_def_id); if let ty::Adt(def, substs) = item_type.kind() { assert!(def.is_union()); - let fields = &def.non_enum_variant().fields; + + fn allowed_union_field<'tcx>( + ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + ) -> bool { + // We don't just accept all !needs_drop fields, due to semver concerns. + match ty.kind() { + ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) + ty::Tuple(tys) => { + // allow tuples of allowed types + tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span)) + } + ty::Array(elem, _len) => { + // Like `Copy`, we do *not* special-case length 0. + allowed_union_field(*elem, tcx, param_env, span) + } + _ => { + // Fallback case: allow `ManuallyDrop` and things that are `Copy`. + ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) + || ty.is_copy_modulo_regions(tcx.at(span), param_env) + } + } + } + let param_env = tcx.param_env(item_def_id); - for field in fields { + for field in &def.non_enum_variant().fields { let field_ty = field.ty(tcx, substs); - if field_ty.needs_drop(tcx, param_env) { + + if !allowed_union_field(field_ty, tcx, param_env, span) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { // We are currently checking the type this field came from, so it must be local. Some(Node::Field(field)) => (field.span, field.ty.span), @@ -439,6 +460,9 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b ) .emit(); return false; + } else if field_ty.needs_drop(tcx, param_env) { + // This should never happen. But we can get here e.g. in case of name resolution errors. + tcx.sess.delay_span_bug(span, "we should never accept maybe-dropping union fields"); } } } else { @@ -448,13 +472,14 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b } /// Check that a `static` is inhabited. -fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { +fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { // Make sure statics are inhabited. // Other parts of the compiler assume that there are no uninhabited places. In principle it // would be enough to check this for `extern` statics, as statics with an initializer will // have UB during initialization if they are uninhabited, but there also seems to be no good // reason to allow any statics to be uninhabited. let ty = tcx.type_of(def_id); + let span = tcx.def_span(def_id); let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) { Ok(l) => l, // Foreign statics that overflow their allowed size should emit an error @@ -501,9 +526,9 @@ pub(super) fn check_opaque<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, substs: SubstsRef<'tcx>, - span: Span, origin: &hir::OpaqueTyOrigin, ) { + let span = tcx.def_span(def_id); check_opaque_for_inheriting_lifetimes(tcx, def_id, span); if tcx.type_of(def_id).references_error() { return; @@ -527,7 +552,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( struct FoundParentLifetime; struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { type BreakTy = FoundParentLifetime; fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -561,7 +586,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( selftys: Vec<(Span, Option<String>)>, } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -707,14 +732,13 @@ fn check_opaque_meets_bounds<'tcx>( let param_env = tcx.param_env(defining_use_anchor); tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| { - let inh = Inherited::new(infcx, def_id); - let infcx = &inh.infcx; + let ocx = ObligationCtxt::new(&infcx); let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); let misc_cause = traits::ObligationCause::misc(span, hir_id); match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) { - Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), + Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), Err(ty_err) => { tcx.sess.delay_span_bug( span, @@ -728,11 +752,11 @@ fn check_opaque_meets_bounds<'tcx>( // hidden type is well formed even without those bounds. let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx); - inh.register_predicate(Obligation::new(misc_cause, param_env, predicate)); + ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } @@ -742,10 +766,11 @@ fn check_opaque_meets_bounds<'tcx>( hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias => { - // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. - let fcx = FnCtxt::new(&inh, param_env, hir_id); - fcx.regionck_item(hir_id, span, FxHashSet::default()); + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors( + defining_use_anchor, + &outlives_environment, + ); } } @@ -754,7 +779,7 @@ fn check_opaque_meets_bounds<'tcx>( }); } -pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { +fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { debug!( "check_item_type(it.def_id={:?}, it.name={})", id.def_id, @@ -764,8 +789,8 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { match tcx.def_kind(id.def_id) { DefKind::Static(..) => { tcx.ensure().typeck(id.def_id); - maybe_check_static_with_link_section(tcx, id.def_id, tcx.def_span(id.def_id)); - check_static_inhabited(tcx, id.def_id, tcx.def_span(id.def_id)); + maybe_check_static_with_link_section(tcx, id.def_id); + check_static_inhabited(tcx, id.def_id); } DefKind::Const => { tcx.ensure().typeck(id.def_id); @@ -775,7 +800,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else { return; }; - check_enum(tcx, item.span, &enum_definition.variants, item.def_id); + check_enum(tcx, &enum_definition.variants, item.def_id); } DefKind::Fn => {} // entirely within check_item_body DefKind::Impl => { @@ -826,10 +851,10 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } } DefKind::Struct => { - check_struct(tcx, id.def_id, tcx.def_span(id.def_id)); + check_struct(tcx, id.def_id); } DefKind::Union => { - check_union(tcx, id.def_id, tcx.def_span(id.def_id)); + check_union(tcx, id.def_id); } DefKind::OpaqueTy => { let item = tcx.hir().item(id); @@ -842,7 +867,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { // See https://github.com/rust-lang/rust/issues/75100 if !tcx.sess.opts.actually_rustdoc { let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id()); - check_opaque(tcx, item.def_id, substs, item.span, &origin); + check_opaque(tcx, item.def_id, substs, &origin); } } DefKind::TyAlias => { @@ -906,7 +931,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { - check_static_inhabited(tcx, def_id, item.span); + check_static_inhabited(tcx, def_id); } _ => {} } @@ -916,10 +941,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { DefKind::GlobalAsm => { let it = tcx.hir().item(id); let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; - for_item(tcx, it).with_fcx(|fcx| { - fcx.check_asm(asm, it.hir_id()); - Default::default() - }) + InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id()); } _ => {} } @@ -1039,7 +1061,6 @@ fn check_impl_items_against_trait<'tcx>( compare_impl_method( tcx, &ty_impl_item, - impl_item.span, &ty_trait_item, impl_trait_ref, opt_trait_span, @@ -1099,17 +1120,20 @@ fn check_impl_items_against_trait<'tcx>( } if !missing_items.is_empty() { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); - missing_items_err(tcx, impl_span, &missing_items, full_impl_span); + missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span); } if let Some(missing_items) = must_implement_one_of { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); let attr_span = tcx .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of) .map(|attr| attr.span); - missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span); + missing_items_must_implement_one_of_err( + tcx, + tcx.def_span(impl_id), + missing_items, + attr_span, + ); } } } @@ -1305,7 +1329,6 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD if !adt.repr().transparent() { return; } - let sp = tcx.sess.source_map().guess_head_span(sp); if adt.is_union() && !tcx.features().transparent_unions { feature_err( @@ -1325,7 +1348,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD } } - // For each field, figure out if it's known to be a ZST and align(1) + // For each field, figure out if it's known to be a ZST and align(1), with "known" + // respecting #[non_exhaustive] attributes. let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); let param_env = tcx.param_env(field.did); @@ -1334,16 +1358,56 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD let span = tcx.hir().span_if_local(field.did).unwrap(); let zst = layout.map_or(false, |layout| layout.is_zst()); let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1); - (span, zst, align1) + if !zst { + return (span, zst, align1, None); + } + + fn check_non_exhaustive<'tcx>( + tcx: TyCtxt<'tcx>, + t: Ty<'tcx>, + ) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> { + match t.kind() { + ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), + ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), + ty::Adt(def, subst) => { + if !def.did().is_local() { + let non_exhaustive = def.is_variant_list_non_exhaustive() + || def + .variants() + .iter() + .any(ty::VariantDef::is_field_list_non_exhaustive); + let has_priv = def.all_fields().any(|f| !f.vis.is_public()); + if non_exhaustive || has_priv { + return ControlFlow::Break(( + def.descr(), + def.did(), + subst, + non_exhaustive, + )); + } + } + def.all_fields() + .map(|field| field.ty(tcx, subst)) + .try_for_each(|t| check_non_exhaustive(tcx, t)) + } + _ => ControlFlow::Continue(()), + } + } + + (span, zst, align1, check_non_exhaustive(tcx, ty).break_value()) }); - let non_zst_fields = - field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); + let non_zst_fields = field_infos + .clone() + .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None }); let non_zst_count = non_zst_fields.clone().count(); if non_zst_count >= 2 { bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); } - for (span, zst, align1) in field_infos { + let incompatible_zst_fields = + field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count(); + let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2; + for (span, zst, align1, non_exhaustive) in field_infos { if zst && !align1 { struct_span_err!( tcx.sess, @@ -1355,17 +1419,32 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD .span_label(span, "has alignment larger than 1") .emit(); } + if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive { + tcx.struct_span_lint_hir( + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), + span, + |lint| { + let note = if non_exhaustive { + "is marked with `#[non_exhaustive]`" + } else { + "contains private fields" + }; + let field_ty = tcx.def_path_str_with_substs(def_id, substs); + lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types") + .note(format!("this {descr} contains `{field_ty}`, which {note}, \ + and makes it not a breaking change to become non-zero-sized in the future.")) + .emit(); + }, + ) + } } } #[allow(trivial_numeric_casts)] -fn check_enum<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - vs: &'tcx [hir::Variant<'tcx>], - def_id: LocalDefId, -) { +fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) { let def = tcx.adt_def(def_id); + let sp = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() { @@ -1543,12 +1622,6 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { } } -pub(super) use wfcheck::check_item_well_formed; - -pub(super) use wfcheck::check_trait_item as check_trait_item_well_formed; - -pub(super) use wfcheck::check_impl_item as check_impl_item_well_formed; - fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed { struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") .span_label(span, "recursive `async fn`") @@ -1591,8 +1664,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E } else { let mut multispan: MultiSpan = spans.clone().into(); for span in spans { - multispan - .push_span_label(span, "this returned value is of `!` type".to_string()); + multispan.push_span_label(span, "this returned value is of `!` type"); } err.span_note(multispan, "these returned values have a concrete \"never\" type"); } @@ -1609,7 +1681,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) { struct OpaqueTypeCollector(Vec<DefId>); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match *t.kind() { ty::Opaque(def, _) => { diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index cce1130511944..1681e6af81239 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -10,12 +10,10 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; -use rustc_infer::traits::ObligationCauseCode; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::InternalSubsts; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; -use rustc_span::DUMMY_SP; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; @@ -429,14 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in this binder we are creating. assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); let bound_sig = expected_sig.sig.map_bound(|sig| { - let output = self.hide_parent_opaque_types( - sig.output(), - expected_sig.cause_span.unwrap_or(DUMMY_SP), - body.id().hir_id, - ); self.tcx.mk_fn_sig( sig.inputs().iter().cloned(), - output, + sig.output(), sig.c_variadic, hir::Unsafety::Normal, Abi::RustCall, @@ -608,23 +601,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // function. Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { debug!("closure is async fn body"); - self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { - // AFAIK, deducing the future output - // always succeeds *except* in error cases - // like #65159. I'd like to return Error - // here, but I can't because I can't - // easily (and locally) prove that we - // *have* reported an - // error. --nikomatsakis - astconv.ty_infer(None, decl.output.span()) - }) + self.deduce_future_output_from_obligations(expr_def_id, body.id().hir_id) + .unwrap_or_else(|| { + // AFAIK, deducing the future output + // always succeeds *except* in error cases + // like #65159. I'd like to return Error + // here, but I can't because I can't + // easily (and locally) prove that we + // *have* reported an + // error. --nikomatsakis + astconv.ty_infer(None, decl.output.span()) + }) } _ => astconv.ty_infer(None, decl.output.span()), }, }; - let supplied_return = - self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id); let result = ty::Binder::bind_with_vars( self.tcx.mk_fn_sig( @@ -645,18 +637,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result } - fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> { - let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars( - ty, - body_id, - span, - ObligationCauseCode::MiscObligation, - self.param_env, - ); - self.register_predicates(obligations); - value - } - /// Invoked when we are translating the generator that results /// from desugaring an `async fn`. Returns the "sugared" return /// type of the `async fn` -- that is, the return type that the @@ -664,15 +644,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Future<Output = T>`, so we do this by searching through the /// obligations to extract the `T`. #[instrument(skip(self), level = "debug")] - fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> { + fn deduce_future_output_from_obligations( + &self, + expr_def_id: DefId, + body_id: hir::HirId, + ) -> Option<Ty<'tcx>> { let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") }); let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); - let (def_id, substs) = match *ret_ty.kind() { - ty::Opaque(def_id, substs) => (def_id, substs), + + let get_future_output = |predicate: ty::Predicate<'tcx>, span| { + // Search for a pending obligation like + // + // `<R as Future>::Output = T` + // + // where R is the return type we are expecting. This type `T` + // will be our output. + let bound_predicate = predicate.kind(); + if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() { + self.deduce_future_output_from_projection( + span, + bound_predicate.rebind(proj_predicate), + ) + } else { + None + } + }; + + let output_ty = match *ret_ty.kind() { + ty::Infer(ty::TyVar(ret_vid)) => { + self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { + get_future_output(obligation.predicate, obligation.cause.span) + })? + } + ty::Opaque(def_id, substs) => self + .tcx + .bound_explicit_item_bounds(def_id) + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?, ty::Error(_) => return None, _ => span_bug!( self.tcx.def_span(expr_def_id), @@ -680,32 +693,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), }; - let item_bounds = self.tcx.bound_explicit_item_bounds(def_id); - - // Search for a pending obligation like - // - // `<R as Future>::Output = T` - // - // where R is the return type we are expecting. This type `T` - // will be our output. - let output_ty = item_bounds - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .find_map(|(predicate, span)| { - let bound_predicate = predicate.subst(self.tcx, substs).kind(); - if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() - { - self.deduce_future_output_from_projection( - span.0, - bound_predicate.rebind(proj_predicate), - ) - } else { - None - } - }); + // async fn that have opaque types in their return type need to redo the conversion to inference variables + // as they fetch the still opaque version from the signature. + let InferOk { value: output_ty, obligations } = self + .replace_opaque_types_with_inference_vars( + output_ty, + body_id, + self.tcx.def_span(expr_def_id), + self.param_env, + ); + self.register_predicates(obligations); debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); - output_ty + Some(output_ty) } /// Given a projection like diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 43fc49c680104..9c9a2096ae9a4 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -50,9 +50,9 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; @@ -1577,8 +1577,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let parent_id = fcx.tcx.hir().get_parent_node(id); let parent = fcx.tcx.hir().get(parent_id); if let Some(expr) = expression - && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) = parent - && !matches!(fcx.tcx.hir().body(*body).value.kind, hir::ExprKind::Block(..)) + && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent + && !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..)) { fcx.suggest_missing_semicolon(&mut err, expr, expected, true); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 95c82a7d2c3d8..a53217ef81882 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,3 +1,6 @@ +use super::potentially_plural_count; +use crate::check::regionck::OutlivesEnvironmentExt; +use crate::check::wfcheck; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; @@ -5,7 +8,8 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; -use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; @@ -14,11 +18,11 @@ use rustc_middle::ty::{self, DefIdTree}; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, +}; use std::iter; -use super::{potentially_plural_count, FnCtxt, Inherited}; - /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. /// @@ -31,14 +35,13 @@ use super::{potentially_plural_count, FnCtxt, Inherited}; pub(crate) fn compare_impl_method<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &ty::AssocItem, - impl_m_span: Span, trait_m: &ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, trait_item_span: Option<Span>, ) { debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); - let impl_m_span = tcx.sess.source_map().guess_head_span(impl_m_span); + let impl_m_span = tcx.def_span(impl_m.def_id); if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) { return; @@ -78,10 +81,11 @@ fn compare_predicate_entailment<'tcx>( let trait_to_impl_substs = impl_trait_ref.substs; // This node-id should be used for the `body_id` field on each - // `ObligationCause` (and the `FnCtxt`). This is what - // `regionck_item` expects. + // `ObligationCause` (and the `FnCtxt`). + // + // FIXME(@lcnr): remove that after removing `cause.body_id` from + // obligations. let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); - // We sometimes modify the span further down. let mut cause = ObligationCause::new( impl_m_span, @@ -169,14 +173,7 @@ fn compare_predicate_entailment<'tcx>( let trait_m_predicates = tcx.predicates_of(trait_m.def_id); // Check region bounds. - check_region_bounds_on_impl_item( - tcx, - impl_m_span, - impl_m, - trait_m, - &trait_m_generics, - &impl_m_generics, - )?; + check_region_bounds_on_impl_item(tcx, impl_m, trait_m, &trait_m_generics, &impl_m_generics)?; // Create obligations for each predicate declared by the impl // definition in the context of the trait's parameter @@ -208,24 +205,21 @@ fn compare_predicate_entailment<'tcx>( Reveal::UserFacing, hir::Constness::NotConst, ); - let param_env = - traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause); + let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); - tcx.infer_ctxt().enter(|infcx| { - let inh = Inherited::new(infcx, impl_m.def_id.expect_local()); - let infcx = &inh.infcx; + tcx.infer_ctxt().enter(|ref infcx| { + let ocx = ObligationCtxt::new(infcx); debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) { let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, param_env, normalize_cause, predicate); - inh.register_predicates(obligations); + ocx.register_obligations(obligations); let cause = ObligationCause::new( span, impl_m_hir_id, @@ -234,7 +228,7 @@ fn compare_predicate_entailment<'tcx>( trait_item_def_id: trait_m.def_id, }, ); - inh.register_predicate(traits::Obligation::new(cause, param_env, predicate)); + ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate)); } // We now need to check that the signature of the impl method is @@ -260,32 +254,31 @@ fn compare_predicate_entailment<'tcx>( infer::HigherRankedType, tcx.fn_sig(impl_m.def_id), ); - let impl_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig); + + let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id); + let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); - let trait_sig = - inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); + let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig); // Add the resulting inputs and output as well-formed. wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); - let sub_result = infcx.at(&cause, param_env).sup(trait_fty, impl_fty).map( - |InferOk { obligations, .. }| { - // FIXME: We'd want to keep more accurate spans than "the method signature" when - // processing the comparison between the trait and impl fn, but we sadly lose them - // and point at the whole signature when a trait bound or specific input or output - // type would be more appropriate. In other places we have a `Vec<Span>` - // corresponding to their `Vec<Predicate>`, but we don't have that here. - // Fixing this would improve the output of test `issue-83765.rs`. - inh.register_predicates(obligations); - }, - ); + // FIXME: We'd want to keep more accurate spans than "the method signature" when + // processing the comparison between the trait and impl fn, but we sadly lose them + // and point at the whole signature when a trait bound or specific input or output + // type would be more appropriate. In other places we have a `Vec<Span>` + // corresponding to their `Vec<Predicate>`, but we don't have that here. + // Fixing this would improve the output of test `issue-83765.rs`. + let sub_result = infcx + .at(&cause, param_env) + .sup(trait_fty, impl_fty) + .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok)); if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); @@ -297,7 +290,7 @@ fn compare_predicate_entailment<'tcx>( let mut diag = struct_span_err!( tcx.sess, - cause.span(tcx), + cause.span(), E0053, "method `{}` has an incompatible type for trait", trait_m.name @@ -391,7 +384,7 @@ fn compare_predicate_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.report_fulfillment_errors(&errors, None, false); return Err(reported); @@ -399,8 +392,12 @@ fn compare_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id); - fcx.regionck_item(impl_m_hir_id, impl_m_span, wf_tys); + let mut outlives_environment = OutlivesEnvironment::new(param_env); + outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id); + infcx.check_region_obligations_and_report_errors( + impl_m.def_id.expect_local(), + &outlives_environment, + ); Ok(()) }) @@ -408,7 +405,6 @@ fn compare_predicate_entailment<'tcx>( fn check_region_bounds_on_impl_item<'tcx>( tcx: TyCtxt<'tcx>, - span: Span, impl_m: &ty::AssocItem, trait_m: &ty::AssocItem, trait_generics: &ty::Generics, @@ -434,25 +430,25 @@ fn check_region_bounds_on_impl_item<'tcx>( // are zero. Since I don't quite know how to phrase things at // the moment, give a kind of vague error message. if trait_params != impl_params { - let item_kind = assoc_item_kind_str(impl_m); - let def_span = tcx.sess.source_map().guess_head_span(span); - let span = impl_m - .def_id - .as_local() - .and_then(|did| tcx.hir().get_generics(did)) - .map_or(def_span, |g| g.span); - let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| { - let def_sp = tcx.sess.source_map().guess_head_span(sp); - trait_m - .def_id - .as_local() - .and_then(|did| tcx.hir().get_generics(did)) - .map_or(def_sp, |g| g.span) - }); + let span = tcx + .hir() + .get_generics(impl_m.def_id.expect_local()) + .expect("expected impl item to have generics or else we can't compare them") + .span; + let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() { + Some( + tcx.hir() + .get_generics(local_def_id) + .expect("expected trait item to have generics or else we can't compare them") + .span, + ) + } else { + None + }; let reported = tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { span, - item_kind, + item_kind: assoc_item_kind_str(impl_m), ident: impl_m.ident(tcx), generics_span, }); @@ -492,7 +488,7 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) } - _ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)), + _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)), } } @@ -548,7 +544,7 @@ fn compare_self_type<'tcx>( if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { err.span_label(span, format!("trait method declared without `{self_descr}`")); } else { - err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } let reported = err.emit(); return Err(reported); @@ -568,7 +564,7 @@ fn compare_self_type<'tcx>( if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) { err.span_label(span, format!("`{self_descr}` used in trait")); } else { - err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } let reported = err.emit(); return Err(reported); @@ -807,7 +803,7 @@ fn compare_number_of_method_arguments<'tcx>( ), ); } else { - err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx)); + err.note_trait_signature(trait_m.name, trait_m.signature(tcx)); } err.span_label( impl_span, @@ -1041,8 +1037,7 @@ fn compare_generic_param_kinds<'tcx>( err.span_label(trait_header_span, ""); err.span_label(param_trait_span, make_param_message("expected", param_trait)); - let impl_header_span = - tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id))); + let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id)); err.span_label(impl_header_span, ""); err.span_label(param_impl_span, make_param_message("found", param_impl)); @@ -1065,8 +1060,7 @@ pub(crate) fn compare_const_impl<'tcx>( tcx.infer_ctxt().enter(|infcx| { let param_env = tcx.param_env(impl_c.def_id); - let inh = Inherited::new(infcx, impl_c.def_id.expect_local()); - let infcx = &inh.infcx; + let ocx = ObligationCtxt::new(&infcx); // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially @@ -1089,20 +1083,18 @@ pub(crate) fn compare_const_impl<'tcx>( ); // There is no "body" here, so just pass dummy id. - let impl_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, impl_ty); + let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty); debug!("compare_const_impl: impl_ty={:?}", impl_ty); - let trait_ty = - inh.normalize_associated_types_in(impl_c_span, impl_c_hir_id, param_env, trait_ty); + let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty); debug!("compare_const_impl: trait_ty={:?}", trait_ty); let err = infcx .at(&cause, param_env) .sup(trait_ty, impl_ty) - .map(|ok| inh.register_infer_ok_obligations(ok)); + .map(|ok| ocx.register_infer_ok_obligations(ok)); if let Err(terr) = err { debug!( @@ -1149,14 +1141,15 @@ pub(crate) fn compare_const_impl<'tcx>( // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); return; } - let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id); - fcx.regionck_item(impl_c_hir_id, impl_c_span, FxHashSet::default()); + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx + .resolve_regions_and_report_errors(impl_c.def_id.expect_local(), &outlives_environment); }); } @@ -1202,7 +1195,6 @@ fn compare_type_predicate_entailment<'tcx>( check_region_bounds_on_impl_item( tcx, - impl_ty_span, impl_ty, trait_ty, &trait_ty_generics, @@ -1247,15 +1239,9 @@ fn compare_type_predicate_entailment<'tcx>( Reveal::UserFacing, hir::Constness::NotConst, ); - let param_env = traits::normalize_param_env_or_error( - tcx, - impl_ty.def_id, - param_env, - normalize_cause.clone(), - ); + let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone()); tcx.infer_ctxt().enter(|infcx| { - let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); - let infcx = &inh.infcx; + let ocx = ObligationCtxt::new(&infcx); debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); @@ -1265,13 +1251,13 @@ fn compare_type_predicate_entailment<'tcx>( let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate); - inh.register_predicates(obligations); - inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); + ocx.register_obligations(obligations); + ocx.register_obligation(traits::Obligation::new(cause.clone(), param_env, predicate)); } // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.report_fulfillment_errors(&errors, None, false); return Err(reported); @@ -1279,8 +1265,11 @@ fn compare_type_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); - fcx.regionck_item(impl_ty_hir_id, impl_ty_span, FxHashSet::default()); + let outlives_environment = OutlivesEnvironment::new(param_env); + infcx.check_region_obligations_and_report_errors( + impl_ty.def_id.expect_local(), + &outlives_environment, + ); Ok(()) }) @@ -1444,10 +1433,9 @@ pub fn check_type_bounds<'tcx>( impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); tcx.infer_ctxt().enter(move |infcx| { - let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); - let infcx = &inh.infcx; - let mut selcx = traits::SelectionContext::new(&infcx); + let ocx = ObligationCtxt::new(&infcx); + let mut selcx = traits::SelectionContext::new(&infcx); let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); let normalize_cause = ObligationCause::new( impl_ty_span, @@ -1490,13 +1478,13 @@ pub fn check_type_bounds<'tcx>( debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; - inh.register_predicates(obligations); - inh.register_predicate(obligation); + ocx.register_obligations(obligations); + ocx.register_obligation(obligation); } // Check that all obligations are satisfied by the implementation's // version. - let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { let reported = infcx.report_fulfillment_errors(&errors, None, false); return Err(reported); @@ -1504,12 +1492,18 @@ pub fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); let implied_bounds = match impl_ty.container { ty::TraitContainer(_) => FxHashSet::default(), - ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span), + ty::ImplContainer(def_id) => { + wfcheck::impl_implied_bounds(tcx, param_env, def_id.expect_local(), impl_ty_span) + } }; - fcx.regionck_item(impl_ty_hir_id, impl_ty_span, implied_bounds); + let mut outlives_environment = OutlivesEnvironment::new(param_env); + outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id); + infcx.check_region_obligations_and_report_errors( + impl_ty.def_id.expect_local(), + &outlives_environment, + ); Ok(()) }) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 961bbc426613c..740261cfe743b 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, hir::Path { res: hir::def::Res::Local(hir_id), .. }, )) => { - if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) { + if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) { let parent = self.tcx.hir().get_parent_node(pat.hir_id); primary_span = pat.span; secondary_span = pat.span; @@ -317,9 +317,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .is_diagnostic_item(sym::Result, expected_adt.did()) { - vec!["Ok(())".to_string()] + vec!["Ok(())"] } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) { - vec!["None".to_string(), "Some(())".to_string()] + vec!["None", "Some(())"] } else { return; }; @@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let param_parent = self.tcx.hir().get_parent_node(*param_hir_id); let Some(Node::Expr(hir::Expr { hir_id: expr_hir_id, - kind: hir::ExprKind::Closure { fn_decl: closure_fn_decl, .. }, + kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }), .. })) = self.tcx.hir().find(param_parent) else { return None; @@ -760,7 +760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(call_span) = iter::successors(Some(expr.span), |s| s.parent_callsite()) .find(|&s| sp.contains(s)) - && sm.span_to_snippet(call_span).is_ok() + && sm.is_span_accessible(call_span) { return Some(( sp.with_hi(call_span.lo()), @@ -773,7 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } if sp.contains(expr.span) - && sm.span_to_snippet(expr.span).is_ok() + && sm.is_span_accessible(expr.span) { return Some(( sp.with_hi(expr.span.lo()), diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 307064327c5a3..72095c408075c 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -1,5 +1,6 @@ -use crate::check::regionck::RegionCtxt; -use crate::hir; +// FIXME(@lcnr): Move this module out of `rustc_typeck`. +// +// We don't do any drop checking during hir typeck. use crate::hir::def_id::{DefId, LocalDefId}; use rustc_errors::{struct_span_err, ErrorGuaranteed}; use rustc_middle::ty::error::TypeError; @@ -7,9 +8,6 @@ use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::IgnoreRegions; use rustc_middle::ty::{self, Predicate, Ty, TyCtxt}; -use rustc_span::Span; -use rustc_trait_selection::traits::query::dropck_outlives::AtExt; -use rustc_trait_selection::traits::ObligationCause; /// This function confirms that the `Drop` implementation identified by /// `drop_impl_did` is not any more specialized than the type it is @@ -206,6 +204,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok() && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok() } + (ty::PredicateKind::WellFormed(arg_a), ty::PredicateKind::WellFormed(arg_b)) => { + relator.relate(predicate.rebind(arg_a), p.rebind(arg_b)).is_ok() + } _ => predicate == p, } }; @@ -228,23 +229,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( result } -/// This function is not only checking that the dropck obligations are met for -/// the given type, but it's also currently preventing non-regular recursion in -/// types from causing stack overflows (dropck_no_diverge_on_nonregular_*.rs). -pub(crate) fn check_drop_obligations<'a, 'tcx>( - rcx: &mut RegionCtxt<'a, 'tcx>, - ty: Ty<'tcx>, - span: Span, - body_id: hir::HirId, -) { - debug!("check_drop_obligations typ: {:?}", ty); - - let cause = &ObligationCause::misc(span, body_id); - let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty); - debug!("dropck_outlives = {:#?}", infer_ok); - rcx.fcx.register_infer_ok_obligations(infer_ok); -} - // This is an implementation of the TypeRelation trait with the // aim of simply comparing for equality (without side-effects). // It is not intended to be used anywhere else other than here. diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b4476d5c59b2b..02e493f725864 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -35,7 +35,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, HirId, QPath}; +use rustc_hir::{Closure, ExprKind, HirId, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -44,11 +44,11 @@ use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::TypeError::FieldMisMatch; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable}; +use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeVisitable}; use rustc_session::parse::feature_err; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; -use rustc_span::source_map::Span; +use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi::RustIntrinsic; @@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self, expr), level = "debug")] - pub(super) fn check_expr_kind( + fn check_expr_kind( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, @@ -282,11 +282,13 @@ impl<'a, 'tcx> FnCtxt<'a, '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), + ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { self.check_expr_assign(expr, expected, lhs, rhs, span) } - ExprKind::AssignOp(op, lhs, rhs) => self.check_binop_assign(expr, op, lhs, rhs), + ExprKind::AssignOp(op, lhs, rhs) => { + self.check_binop_assign(expr, op, lhs, rhs, expected) + } ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr), ExprKind::AddrOf(kind, mutbl, oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) @@ -319,7 +321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Match(discrim, arms, match_src) => { self.check_match(expr, &discrim, arms, expected, match_src) } - ExprKind::Closure { capture_clause, fn_decl, body, movability, .. } => { + ExprKind::Closure(&Closure { capture_clause, fn_decl, body, movability, .. }) => { self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected) } ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected), @@ -404,14 +406,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } hir::UnOp::Not => { - let result = self.check_user_unop(expr, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) { oprnd_t = result; } } hir::UnOp::Neg => { - let result = self.check_user_unop(expr, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop, expected_inner); // If it's builtin, we can reuse the type, this helps inference. if !oprnd_t.is_numeric() { oprnd_t = result; @@ -997,26 +999,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce(self, &self.misc(sp), then_expr, then_ty); if let Some(else_expr) = opt_else_expr { - let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) { - // todo introduce `check_expr_with_expectation(.., Expectation::LetElse)` - // for errors that point to the offending expression rather than the entire block. - // We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no - // way to detect that the expected type originated from let-else and provide - // a customized error. - let else_ty = self.check_expr(else_expr); - let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse); - - if let Some(mut err) = - self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) - { - err.emit(); - self.tcx.ty_error() - } else { - else_ty - } - } else { - self.check_expr_with_expectation(else_expr, expected) - }; + let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); @@ -1873,7 +1856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let remaining_private_fields_len = remaining_private_fields.len(); let names = match &remaining_private_fields .iter() - .map(|(name, _, _)| name.to_string()) + .map(|(name, _, _)| name) .collect::<Vec<_>>()[..] { _ if remaining_private_fields_len > 6 => String::new(), @@ -2162,14 +2145,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if !expr_t.is_primitive_ty() { self.ban_nonexisting_field(field, base, expr, expr_t); } else { - type_error_struct!( + let field_name = field.to_string(); + let mut err = type_error_struct!( self.tcx().sess, field.span, expr_t, E0610, "`{expr_t}` is a primitive type and therefore doesn't have fields", - ) - .emit(); + ); + let is_valid_suffix = |field: String| { + if field == "f32" || field == "f64" { + return true; + } + let mut chars = field.chars().peekable(); + match chars.peek() { + Some('e') | Some('E') => { + chars.next(); + if let Some(c) = chars.peek() + && !c.is_numeric() && *c != '-' && *c != '+' + { + return false; + } + while let Some(c) = chars.peek() { + if !c.is_numeric() { + break; + } + chars.next(); + } + } + _ => (), + } + let suffix = chars.collect::<String>(); + suffix.is_empty() || suffix == "f32" || suffix == "f64" + }; + if let ty::Infer(ty::IntVar(_)) = expr_t.kind() + && let ExprKind::Lit(Spanned { + node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed), + .. + }) = base.kind + && !base.span.from_expansion() + && is_valid_suffix(field_name) + { + err.span_suggestion_verbose( + field.span.shrink_to_lo(), + "If the number is meant to be a floating point number, consider adding a `0` after the period", + '0', + Applicability::MaybeIncorrect, + ); + } + err.emit(); } self.tcx().ty_error() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index ea7ebdf91d012..d33b5b2140362 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -23,6 +23,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{ self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, }; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef, ToPredicate, Ty, UserType, @@ -36,7 +37,6 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, - WellFormedLoc, }; use std::collections::hash_map::Entry; @@ -156,6 +156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); } + #[instrument(level = "debug", skip(self))] pub(in super::super) fn write_resolution( &self, hir_id: hir::HirId, @@ -164,8 +165,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); } + #[instrument(level = "debug", skip(self))] pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { - debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); self.write_substs(hir_id, method.substs); @@ -373,29 +374,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result, spans) } - /// Convenience method which tracks extra diagnostic information for normalization - /// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item - /// whose type is being wf-checked - this is used to construct a more precise span if - /// an error occurs. - /// - /// It is never necessary to call this method - calling `normalize_associated_types_in` will - /// just result in a slightly worse diagnostic span, and will still be sound. - pub(in super::super) fn normalize_associated_types_in_wf<T>( - &self, - span: Span, - value: T, - loc: WellFormedLoc, - ) -> T - where - T: TypeFoldable<'tcx>, - { - self.inh.normalize_associated_types_in_with_cause( - ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(loc))), - self.param_env, - value, - ) - } - pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: T) -> T where T: TypeFoldable<'tcx>, @@ -435,6 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))), + output_pred: None, }, ), self.param_env, @@ -494,7 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t); - self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); + self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None)); t } @@ -524,7 +503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_wf_obligation( c.into(), self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, + ObligationCauseCode::WellFormed(None), ); c } @@ -542,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_wf_obligation( c.into(), self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, + ObligationCauseCode::WellFormed(None), ); c } @@ -556,7 +535,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // sufficiently enforced with erased regions. =) fn can_contain_user_lifetime_bounds<T>(t: T) -> bool where - T: TypeFoldable<'tcx>, + T: TypeVisitable<'tcx>, { t.has_free_regions() || t.has_projections() || t.has_infer_types() } @@ -605,7 +584,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for arg in substs.iter().filter(|arg| { matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) }) { - self.register_wf_obligation(arg, expr.span, traits::MiscObligation); + self.register_wf_obligation(arg, expr.span, traits::WellFormed(None)); } } @@ -1034,7 +1013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); sp.push_span_label( rcvr.span, - "you probably want to use this value after calling the method...".to_string(), + "you probably want to use this value after calling the method...", ); err.span_note( sp, @@ -1424,7 +1403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } GenericParamDefKind::Const { has_default } => { if !infer_args && has_default { - EarlyBinder(tcx.const_param_default(param.def_id)) + tcx.bound_const_param_default(param.def_id) .subst(tcx, substs.unwrap()) .into() } else { @@ -1537,8 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.emit_inference_failure_err((**self).body_id, sp, ty.into(), vec![], E0282) - .note("type must be known at this point") + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true) .emit(); } let err = self.tcx.ty_error(); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs index b7ba9d9787846..7602f2550e85b 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -1,7 +1,26 @@ use std::cmp; +use rustc_index::vec::IndexVec; use rustc_middle::ty::error::TypeError; +rustc_index::newtype_index! { + pub(crate) struct ExpectedIdx { + DEBUG_FORMAT = "ExpectedIdx({})", + } +} + +rustc_index::newtype_index! { + pub(crate) struct ProvidedIdx { + DEBUG_FORMAT = "ProvidedIdx({})", + } +} + +impl ExpectedIdx { + pub fn to_provided_idx(self) -> ProvidedIdx { + ProvidedIdx::from_usize(self.as_usize()) + } +} + // An issue that might be found in the compatibility matrix #[derive(Debug)] enum Issue { @@ -27,24 +46,24 @@ pub(crate) enum Compatibility<'tcx> { #[derive(Debug)] pub(crate) enum Error<'tcx> { /// The provided argument is the invalid type for the expected input - Invalid(usize, usize, Compatibility<'tcx>), // provided, expected + Invalid(ProvidedIdx, ExpectedIdx, Compatibility<'tcx>), /// There is a missing input - Missing(usize), + Missing(ExpectedIdx), /// There's a superfluous argument - Extra(usize), + Extra(ProvidedIdx), /// Two arguments should be swapped - Swap(usize, usize, usize, usize), + Swap(ProvidedIdx, ProvidedIdx, ExpectedIdx, ExpectedIdx), /// Several arguments should be reordered - Permutation(Vec<(usize, usize)>), // dest_arg, dest_input + Permutation(Vec<(ExpectedIdx, ProvidedIdx)>), } pub(crate) struct ArgMatrix<'tcx> { /// Maps the indices in the `compatibility_matrix` rows to the indices of /// the *user provided* inputs - input_indexes: Vec<usize>, + provided_indices: Vec<ProvidedIdx>, /// Maps the indices in the `compatibility_matrix` columns to the indices /// of the *expected* args - arg_indexes: Vec<usize>, + expected_indices: Vec<ExpectedIdx>, /// The first dimension (rows) are the remaining user provided inputs to /// match and the second dimension (cols) are the remaining expected args /// to match @@ -52,62 +71,64 @@ pub(crate) struct ArgMatrix<'tcx> { } impl<'tcx> ArgMatrix<'tcx> { - pub(crate) fn new<F: FnMut(usize, usize) -> Compatibility<'tcx>>( - minimum_input_count: usize, - provided_arg_count: usize, + pub(crate) fn new<F: FnMut(ProvidedIdx, ExpectedIdx) -> Compatibility<'tcx>>( + provided_count: usize, + expected_input_count: usize, mut is_compatible: F, ) -> Self { - let compatibility_matrix = (0..provided_arg_count) - .map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect()) + let compatibility_matrix = (0..provided_count) + .map(|i| { + (0..expected_input_count) + .map(|j| is_compatible(ProvidedIdx::from_usize(i), ExpectedIdx::from_usize(j))) + .collect() + }) .collect(); ArgMatrix { - input_indexes: (0..provided_arg_count).collect(), - arg_indexes: (0..minimum_input_count).collect(), + provided_indices: (0..provided_count).map(ProvidedIdx::from_usize).collect(), + expected_indices: (0..expected_input_count).map(ExpectedIdx::from_usize).collect(), compatibility_matrix, } } /// Remove a given input from consideration - fn eliminate_input(&mut self, idx: usize) { - self.input_indexes.remove(idx); + fn eliminate_provided(&mut self, idx: usize) { + self.provided_indices.remove(idx); self.compatibility_matrix.remove(idx); } /// Remove a given argument from consideration - fn eliminate_arg(&mut self, idx: usize) { - self.arg_indexes.remove(idx); + fn eliminate_expected(&mut self, idx: usize) { + self.expected_indices.remove(idx); for row in &mut self.compatibility_matrix { row.remove(idx); } } /// "satisfy" an input with a given arg, removing both from consideration - fn satisfy_input(&mut self, input_idx: usize, arg_idx: usize) { - self.eliminate_input(input_idx); - self.eliminate_arg(arg_idx); + fn satisfy_input(&mut self, provided_idx: usize, expected_idx: usize) { + self.eliminate_provided(provided_idx); + self.eliminate_expected(expected_idx); } // Returns a `Vec` of (user input, expected arg) of matched arguments. These // are inputs on the remaining diagonal that match. - fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> { - let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len()); + fn eliminate_satisfied(&mut self) -> Vec<(ProvidedIdx, ExpectedIdx)> { + let num_args = cmp::min(self.provided_indices.len(), self.expected_indices.len()); let mut eliminated = vec![]; - while i > 0 { - let idx = i - 1; - if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) { - eliminated.push((self.input_indexes[idx], self.arg_indexes[idx])); - self.satisfy_input(idx, idx); + for i in (0..num_args).rev() { + if matches!(self.compatibility_matrix[i][i], Compatibility::Compatible) { + eliminated.push((self.provided_indices[i], self.expected_indices[i])); + self.satisfy_input(i, i); } - i -= 1; } - return eliminated; + eliminated } // Find some issue in the compatibility matrix fn find_issue(&self) -> Option<Issue> { let mat = &self.compatibility_matrix; - let ai = &self.arg_indexes; - let ii = &self.input_indexes; + let ai = &self.expected_indices; + let ii = &self.provided_indices; for i in 0..cmp::max(ai.len(), ii.len()) { // If we eliminate the last row, any left-over inputs are considered missing @@ -264,12 +285,15 @@ impl<'tcx> ArgMatrix<'tcx> { // // We'll want to know which arguments and inputs these rows and columns correspond to // even after we delete them. - pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) { - let provided_arg_count = self.input_indexes.len(); + pub(crate) fn find_errors( + mut self, + ) -> (Vec<Error<'tcx>>, IndexVec<ExpectedIdx, Option<ProvidedIdx>>) { + let provided_arg_count = self.provided_indices.len(); let mut errors: Vec<Error<'tcx>> = vec![]; // For each expected argument, the matched *actual* input - let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()]; + let mut matched_inputs: IndexVec<ExpectedIdx, Option<ProvidedIdx>> = + IndexVec::from_elem_n(None, self.expected_indices.len()); // Before we start looking for issues, eliminate any arguments that are already satisfied, // so that an argument which is already spoken for by the input it's in doesn't @@ -280,34 +304,34 @@ impl<'tcx> ArgMatrix<'tcx> { // Without this elimination, the first argument causes the second argument // to show up as both a missing input and extra argument, rather than // just an invalid type. - for (inp, arg) in self.eliminate_satisfied() { - matched_inputs[arg] = Some(inp); + for (provided, expected) in self.eliminate_satisfied() { + matched_inputs[expected] = Some(provided); } - while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 { + while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() { match self.find_issue() { Some(Issue::Invalid(idx)) => { let compatibility = self.compatibility_matrix[idx][idx].clone(); - let input_idx = self.input_indexes[idx]; - let arg_idx = self.arg_indexes[idx]; + let input_idx = self.provided_indices[idx]; + let arg_idx = self.expected_indices[idx]; self.satisfy_input(idx, idx); errors.push(Error::Invalid(input_idx, arg_idx, compatibility)); } Some(Issue::Extra(idx)) => { - let input_idx = self.input_indexes[idx]; - self.eliminate_input(idx); + let input_idx = self.provided_indices[idx]; + self.eliminate_provided(idx); errors.push(Error::Extra(input_idx)); } Some(Issue::Missing(idx)) => { - let arg_idx = self.arg_indexes[idx]; - self.eliminate_arg(idx); + let arg_idx = self.expected_indices[idx]; + self.eliminate_expected(idx); errors.push(Error::Missing(arg_idx)); } Some(Issue::Swap(idx, other)) => { - let input_idx = self.input_indexes[idx]; - let other_input_idx = self.input_indexes[other]; - let arg_idx = self.arg_indexes[idx]; - let other_arg_idx = self.arg_indexes[other]; + let input_idx = self.provided_indices[idx]; + let other_input_idx = self.provided_indices[other]; + let arg_idx = self.expected_indices[idx]; + let other_arg_idx = self.expected_indices[other]; let (min, max) = (cmp::min(idx, other), cmp::max(idx, other)); self.satisfy_input(min, max); // Subtract 1 because we already removed the "min" row @@ -319,13 +343,14 @@ impl<'tcx> ArgMatrix<'tcx> { Some(Issue::Permutation(args)) => { let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect(); - let mut real_idxs = vec![None; provided_arg_count]; + let mut real_idxs: IndexVec<ProvidedIdx, Option<(ExpectedIdx, ProvidedIdx)>> = + IndexVec::from_elem_n(None, provided_arg_count); for (src, dst) in args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst))) { - let src_input_idx = self.input_indexes[src]; - let dst_input_idx = self.input_indexes[dst]; - let dest_arg_idx = self.arg_indexes[dst]; + let src_input_idx = self.provided_indices[src]; + let dst_input_idx = self.provided_indices[dst]; + let dest_arg_idx = self.expected_indices[dst]; real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx)); matched_inputs[dest_arg_idx] = Some(src_input_idx); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 2326c4069e483..89b376442a887 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1,7 +1,10 @@ use crate::astconv::AstConv; use crate::check::coercion::CoerceMany; -use crate::check::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error}; +use crate::check::fn_ctxt::arg_matrix::{ + ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx, +}; use crate::check::gather_locals::Declaration; +use crate::check::intrinsicck::InlineAsmCtxt; use crate::check::method::MethodCallee; use crate::check::Expectation::*; use crate::check::TupleArgumentsFlag::*; @@ -17,27 +20,24 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, Node, QPath}; +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_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; -use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression}; +use rustc_trait_selection::traits::{ + self, ObligationCauseCode, SelectionContext, StatementAsExpression, +}; use std::iter; use std::slice; -enum TupleMatchFound { - None, - Single, - /// Beginning and end Span - Multiple(Span, Span), -} impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&self) { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -60,7 +60,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); for (asm, hir_id) in deferred_asm_checks.drain(..) { let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id); - self.check_asm(asm, enclosing_id); + InlineAsmCtxt::new_in_fn(self).check_asm(asm, enclosing_id); } } @@ -93,7 +93,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args_no_rcvr, false, tuple_arguments, - None, + method.ok().map(|method| method.def_id), ); return self.tcx.ty_error(); } @@ -213,13 +213,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let minimum_input_count = expected_input_tys.len(); let provided_arg_count = provided_args.len(); - // We'll also want to keep track of the fully coerced argument types, for an awkward hack near the end - let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count]; - // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types - let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| { + let demand_compatible = |idx| { let formal_input_ty: Ty<'tcx> = formal_input_tys[idx]; let expected_input_ty: Ty<'tcx> = expected_input_tys[idx]; let provided_arg = &provided_args[idx]; @@ -238,9 +235,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); - // Keep track of these for below - final_arg_types[idx] = Some((checked_ty, coerced_ty)); - // Cause selection errors caused by resolving a single argument to point at the // argument and not the call. This lets us customize the span pointed to in the // fulfillment error to be more accurate. @@ -249,16 +243,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); self.point_at_arg_instead_of_call_if_possible( errors, - &final_arg_types, call_expr, call_span, provided_args, + &expected_input_tys, ); }); - // Make sure we store the resolved type - final_arg_types[idx] = Some((checked_ty, coerced_ty)); - let coerce_error = self .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None) .err(); @@ -287,54 +278,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - // A "softer" version of the helper above, which checks types without persisting them, - // and treats error types differently - // This will allow us to "probe" for other argument orders that would likely have been correct - let check_compatible = |input_idx, arg_idx| { - let formal_input_ty: Ty<'tcx> = formal_input_tys[arg_idx]; - let expected_input_ty: Ty<'tcx> = expected_input_tys[arg_idx]; - - // If either is an error type, we defy the usual convention and consider them to *not* be - // coercible. This prevents our error message heuristic from trying to pass errors into - // every argument. - if formal_input_ty.references_error() || expected_input_ty.references_error() { - return Compatibility::Incompatible(None); - } - - let provided_arg: &hir::Expr<'tcx> = &provided_args[input_idx]; - let expectation = Expectation::rvalue_hint(self, expected_input_ty); - // FIXME: check that this is safe; I don't believe this commits any of the obligations, but I can't be sure. - // - // I had another method of "soft" type checking before, - // but it was failing to find the type of some expressions (like "") - // so I prodded this method and made it pub(super) so I could call it, and it seems to work well. - let checked_ty = self.check_expr_kind(provided_arg, expectation); - - let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); - let can_coerce = self.can_coerce(checked_ty, coerced_ty); - - if !can_coerce { - return Compatibility::Incompatible(None); - } - - let subtyping_result = self - .at(&self.misc(provided_arg.span), self.param_env) - .sup(formal_input_ty, coerced_ty); - - // Same as above: if either the coerce type or the checked type is an error type, - // consider them *not* compatible. - let coercible = - !coerced_ty.references_error() && !checked_ty.references_error() && can_coerce; - - match (coercible, &subtyping_result) { - (true, Ok(_)) => Compatibility::Compatible, - _ => Compatibility::Incompatible(subtyping_result.err()), - } - }; - // To start, we only care "along the diagonal", where we expect every // provided arg to be in the right spot - let mut compatibility = vec![Compatibility::Incompatible(None); provided_args.len()]; + let mut compatibility_diagonal = + vec![Compatibility::Incompatible(None); provided_args.len()]; // Keep track of whether we *could possibly* be satisfied, i.e. whether we're on the happy path // if the wrong number of arguments were supplied, we CAN'T be satisfied, @@ -360,10 +307,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); self.point_at_arg_instead_of_call_if_possible( errors, - &final_arg_types, call_expr, call_span, &provided_args, + &expected_input_tys, ); }) } @@ -392,9 +339,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - let compatible = demand_compatible(idx, &mut final_arg_types); + let compatible = demand_compatible(idx); let is_compatible = matches!(compatible, Compatibility::Compatible); - compatibility[idx] = compatible; + compatibility_diagonal[idx] = compatible; if !is_compatible { call_appears_satisfied = false; @@ -402,654 +349,735 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Logic here is a bit hairy - 'errors: { - // If something above didn't typecheck, we've fallen off the happy path - // and we should make some effort to provide better error messages - if call_appears_satisfied { - break 'errors; + if c_variadic && provided_arg_count < minimum_input_count { + err_code = "E0060"; + } + + for arg in provided_args.iter().skip(minimum_input_count) { + // Make sure we've checked this expr at least once. + let arg_ty = self.check_expr(&arg); + + // If the function is c-style variadic, we skipped a bunch of arguments + // so we need to check those, and write out the types + // Ideally this would be folded into the above, for uniform style + // but c-variadic is already a corner case + if c_variadic { + fn variadic_error<'tcx>( + sess: &'tcx Session, + span: Span, + ty: Ty<'tcx>, + cast_ty: &str, + ) { + use crate::structured_errors::MissingCastForVariadicArg; + + MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); + } + + // There are a few types which get autopromoted when passed via varargs + // in C but we just error out instead and require explicit casts. + let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); + match arg_ty.kind() { + ty::Float(ty::FloatTy::F32) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); + } + ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); + } + ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); + } + ty::FnDef(..) => { + let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); + let ptr_ty = self.resolve_vars_if_possible(ptr_ty); + variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + } + _ => {} + } } + } + + if !call_appears_satisfied { + let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal); + let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic { + minimum_input_count + } else { + provided_arg_count + })); + debug_assert_eq!( + formal_input_tys.len(), + expected_input_tys.len(), + "expected formal_input_tys to be the same size as expected_input_tys" + ); + let formal_and_expected_inputs = IndexVec::from_iter( + formal_input_tys + .iter() + .copied() + .zip(expected_input_tys.iter().copied()) + .map(|vars| self.resolve_vars_if_possible(vars)), + ); - self.set_tainted_by_errors(); + self.report_arg_errors( + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + c_variadic, + err_code, + fn_def_id, + call_span, + call_expr, + ); + } + } - // The algorithm here is inspired by levenshtein distance and longest common subsequence. - // We'll try to detect 4 different types of mistakes: - // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs - // - An input is missing, which isn't satisfied by *any* of the other arguments - // - Some number of arguments have been provided in the wrong order - // - A type is straight up invalid + fn report_arg_errors( + &self, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, + c_variadic: bool, + err_code: &str, + fn_def_id: Option<DefId>, + call_span: Span, + call_expr: &hir::Expr<'tcx>, + ) { + // Next, let's construct the error + let (error_span, full_call_span, ctor_of) = match &call_expr.kind { + hir::ExprKind::Call( + hir::Expr { + span, + kind: + hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, + )), + .. + }, + _, + ) => (call_span, *span, Some(of)), + hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), + hir::ExprKind::MethodCall(path_segment, _, span) => { + let ident_span = path_segment.ident.span; + let ident_span = if let Some(args) = path_segment.args { + ident_span.with_hi(args.span_ext.hi()) + } else { + ident_span + }; + ( + *span, ident_span, None, // methods are never ctors + ) + } + k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), + }; + let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); + let call_name = match ctor_of { + Some(CtorOf::Struct) => "struct", + Some(CtorOf::Variant) => "enum variant", + None => "function", + }; - // First, let's find the errors - let mut compatibility: Vec<_> = compatibility.into_iter().map(Some).collect(); - let (mut errors, matched_inputs) = - ArgMatrix::new(minimum_input_count, provided_arg_count, |i, j| { - if i == j { compatibility[i].take().unwrap() } else { check_compatible(i, j) } - }) - .find_errors(); + // Don't print if it has error types or is just plain `_` + fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { + tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) + } - // Okay, so here's where it gets complicated in regards to what errors - // we emit and how. - // There are 3 different "types" of errors we might encounter. - // 1) Missing/extra/swapped arguments - // 2) Valid but incorrect arguments - // 3) Invalid arguments - // - Currently I think this only comes up with `CyclicTy` - // - // We first need to go through, remove those from (3) and emit those - // as their own error, particularly since they're error code and - // message is special. From what I can tell, we *must* emit these - // here (vs somewhere prior to this function) since the arguments - // become invalid *because* of how they get used in the function. - // It is what it is. - - let found_errors = !errors.is_empty(); - - errors.drain_filter(|error| { - let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; - let expected_ty = expected_input_tys[*arg_idx]; - let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap_or_else(|| tcx.ty_error()); - let cause = &self.misc(provided_args[*input_idx].span); - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { - self.report_and_explain_type_error(trace, e).emit(); - return true; + self.set_tainted_by_errors(); + let tcx = self.tcx; + + // Precompute the provided types and spans, since that's all we typically need for below + let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args + .iter() + .map(|expr| { + let ty = self + .typeck_results + .borrow() + .expr_ty_adjusted_opt(*expr) + .unwrap_or_else(|| tcx.ty_error()); + (self.resolve_vars_if_possible(ty), expr.span) + }) + .collect(); + let callee_expr = match &call_expr.peel_blocks().kind { + hir::ExprKind::Call(callee, _) => Some(*callee), + hir::ExprKind::MethodCall(_, callee, _) => { + if let Some((DefKind::AssocFn, def_id)) = + self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) + && let Some(assoc) = tcx.opt_associated_item(def_id) + && assoc.fn_has_self_parameter + { + Some(&callee[0]) + } else { + None } - false + } + _ => None, + }; + let callee_ty = callee_expr + .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)); + + // A "softer" version of the `demand_compatible`, which checks types without persisting them, + // and treats error types differently + // This will allow us to "probe" for other argument orders that would likely have been correct + let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| { + if provided_idx.as_usize() == expected_idx.as_usize() { + return compatibility_diagonal[provided_idx].clone(); + } + + let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; + // If either is an error type, we defy the usual convention and consider them to *not* be + // coercible. This prevents our error message heuristic from trying to pass errors into + // every argument. + if (formal_input_ty, expected_input_ty).references_error() { + return Compatibility::Incompatible(None); + } + + let (arg_ty, arg_span) = provided_arg_tys[provided_idx]; + + let expectation = Expectation::rvalue_hint(self, expected_input_ty); + let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); + let can_coerce = self.can_coerce(arg_ty, coerced_ty); + if !can_coerce { + return Compatibility::Incompatible(None); + } + + // 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() }); - // We're done if we found errors, but we already emitted them. - // I don't think we *should* be able to enter this bit of code - // (`!call_appears_satisfied`) without *also* finding errors, but we - // don't want to accidentally not emit an error if there is some - // logic bug in the `ArgMatrix` code. - if found_errors && errors.is_empty() { - break 'errors; + // Same as above: if either the coerce type or the checked type is an error type, + // consider them *not* compatible. + let references_error = (coerced_ty, arg_ty).references_error(); + match (references_error, subtyping_error) { + (false, None) => Compatibility::Compatible, + (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), } + }; - // Next, let's construct the error - let (error_span, full_call_span, ctor_of) = match &call_expr.kind { - hir::ExprKind::Call( - hir::Expr { - span, - kind: - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, - )), - .. - }, - _, - ) => (call_span, *span, Some(of)), - hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), - hir::ExprKind::MethodCall(path_segment, _, span) => { - let ident_span = path_segment.ident.span; - let ident_span = if let Some(args) = path_segment.args { - ident_span.with_hi(args.span_ext.hi()) - } else { - ident_span - }; - ( - *span, ident_span, None, // methods are never ctors - ) + // The algorithm here is inspired by levenshtein distance and longest common subsequence. + // We'll try to detect 4 different types of mistakes: + // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs + // - An input is missing, which isn't satisfied by *any* of the other arguments + // - Some number of arguments have been provided in the wrong order + // - A type is straight up invalid + + // First, let's find the errors + let (mut errors, matched_inputs) = + ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible) + .find_errors(); + + // First, check if we just need to wrap some arguments in a tuple. + if let Some((mismatch_idx, terr)) = + compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { + if let Compatibility::Incompatible(Some(terr)) = c { Some((i, terr)) } else { None } + }) + { + // Is the first bad expected argument a tuple? + // Do we have as many extra provided arguments as the tuple's length? + // If so, we might have just forgotten to wrap some args in a tuple. + if let Some(ty::Tuple(tys)) = + formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) + && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() + { + // Wrap up the N provided arguments starting at this position in a tuple. + let provided_as_tuple = tcx.mk_tup( + provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), + ); + + let mut satisfied = true; + // Check if the newly wrapped tuple + rest of the arguments are compatible. + for ((_, expected_ty), provided_ty) in std::iter::zip( + formal_and_expected_inputs.iter().skip(mismatch_idx), + [provided_as_tuple].into_iter().chain( + provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), + ), + ) { + if !self.can_coerce(provided_ty, *expected_ty) { + satisfied = false; + break; + } } - k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), - }; - let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); - let call_name = match ctor_of { - Some(CtorOf::Struct) => "struct", - Some(CtorOf::Variant) => "enum variant", - None => "function", - }; - if c_variadic && provided_arg_count < minimum_input_count { - err_code = "E0060"; - } - // Next special case: The case where we expect a single tuple and - // wrapping all the args in parentheses (or adding a comma to - // already existing parentheses) will result in a tuple that - // satisfies the call. - // This isn't super ideal code, because we copy code from elsewhere - // and somewhat duplicate this. We also delegate to the general type - // mismatch suggestions for the single arg case. - let sugg_tuple_wrap_args = - self.suggested_tuple_wrap(&expected_input_tys, provided_args); - match sugg_tuple_wrap_args { - TupleMatchFound::None => {} - TupleMatchFound::Single => { - let expected_ty = expected_input_tys[0]; - let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap(); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let provided_ty = self.resolve_vars_if_possible(provided_ty); - let cause = &self.misc(provided_args[0].span); - let compatibility = demand_compatible(0, &mut final_arg_types); - let type_error = match compatibility { - Compatibility::Incompatible(Some(error)) => error, - _ => TypeError::Mismatch, + // If they're compatible, suggest wrapping in an arg, and we're done! + // Take some care with spans, so we don't suggest wrapping a macro's + // innards in parenthesis, for example. + if satisfied + && let Some(lo) = + provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span) + && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()] + .span + .find_ancestor_inside(error_span) + { + let mut err; + if tys.len() == 1 { + // A tuple wrap suggestion actually occurs within, + // so don't do anything special here. + err = self.report_and_explain_type_error( + TypeTrace::types( + &self.misc(lo), + true, + formal_and_expected_inputs[mismatch_idx.into()].1, + provided_arg_tys[mismatch_idx.into()].0, + ), + terr, + ); + err.span_label( + full_call_span, + format!("arguments to this {} are incorrect", call_name), + ); + } else { + err = tcx.sess.struct_span_err_with_code( + full_call_span, + &format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count( + formal_and_expected_inputs.len(), + "argument" + ), + potentially_plural_count(provided_args.len(), "argument"), + if provided_args.len() == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(err_code.to_owned()), + ); + err.multipart_suggestion_verbose( + "wrap these arguments in parentheses to construct a tuple", + vec![ + (lo.shrink_to_lo(), "(".to_string()), + (hi.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); }; - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - let mut err = self.report_and_explain_type_error(trace, &type_error); - self.emit_coerce_suggestions( - &mut err, - &provided_args[0], - final_arg_types[0].map(|ty| ty.0).unwrap(), - final_arg_types[0].map(|ty| ty.1).unwrap(), - None, - None, - ); - err.span_label( - full_call_span, - format!("arguments to this {} are incorrect", call_name), - ); - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - err.emit(); - break 'errors; - } - TupleMatchFound::Multiple(start, end) => { - let mut err = tcx.sess.struct_span_err_with_code( - full_call_span, - &format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(minimum_input_count, "argument"), - potentially_plural_count(provided_arg_count, "argument"), - if provided_arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(err_code.to_owned()), - ); - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - err.multipart_suggestion( - "use parentheses to construct a tuple", - vec![(start, '('.to_string()), (end, ')'.to_string())], - Applicability::MachineApplicable, - ); + self.label_fn_like(&mut err, fn_def_id, callee_ty); err.emit(); - break 'errors; + return; } } + } + + // Okay, so here's where it gets complicated in regards to what errors + // we emit and how. + // There are 3 different "types" of errors we might encounter. + // 1) Missing/extra/swapped arguments + // 2) Valid but incorrect arguments + // 3) Invalid arguments + // - Currently I think this only comes up with `CyclicTy` + // + // We first need to go through, remove those from (3) and emit those + // as their own error, particularly since they're error code and + // message is special. From what I can tell, we *must* emit these + // here (vs somewhere prior to this function) since the arguments + // become invalid *because* of how they get used in the function. + // It is what it is. + + if errors.is_empty() { + if cfg!(debug_assertions) { + span_bug!(error_span, "expected errors from argument matrix"); + } else { + tcx.sess + .struct_span_err( + error_span, + "argument type mismatch was detected, \ + but rustc had trouble determining where", + ) + .note( + "we would appreciate a bug report: \ + https://github.com/rust-lang/rust/issues/new", + ) + .emit(); + } + return; + } + + errors.drain_filter(|error| { + let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(error)) = error else { return false }; + let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; + let (expected_ty, _) = formal_and_expected_inputs[*expected_idx]; + let cause = &self.misc(provided_span); + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + if let Some(e) = error { + if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { + self.report_and_explain_type_error(trace, e).emit(); + return true; + } + } + false + }); + + // We're done if we found errors, but we already emitted them. + if errors.is_empty() { + return; + } + + // Okay, now that we've emitted the special errors separately, we + // are only left missing/extra/swapped and mismatched arguments, both + // can be collated pretty easily if needed. + + // Next special case: if there is only one "Incompatible" error, just emit that + if let [ + Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), + ] = &errors[..] + { + let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; + let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; + let cause = &self.misc(provided_arg_span); + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + let mut err = self.report_and_explain_type_error(trace, err); + self.emit_coerce_suggestions( + &mut err, + &provided_args[*provided_idx], + provided_ty, + Expectation::rvalue_hint(self, expected_ty) + .only_has_type(self) + .unwrap_or(formal_ty), + None, + None, + ); + err.span_label( + full_call_span, + format!("arguments to this {} are incorrect", call_name), + ); + // Call out where the function is defined + self.label_fn_like(&mut err, fn_def_id, callee_ty); + err.emit(); + return; + } + + let mut err = if formal_and_expected_inputs.len() == provided_args.len() { + struct_span_err!( + tcx.sess, + full_call_span, + E0308, + "arguments to this {} are incorrect", + call_name, + ) + } else { + tcx.sess.struct_span_err_with_code( + full_call_span, + &format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count(formal_and_expected_inputs.len(), "argument"), + potentially_plural_count(provided_args.len(), "argument"), + if provided_args.len() == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(err_code.to_owned()), + ) + }; + + // As we encounter issues, keep track of what we want to provide for the suggestion + let mut labels = vec![]; + // If there is a single error, we give a specific suggestion; otherwise, we change to + // "did you mean" with the suggested function call + enum SuggestionText { + None, + Provide(bool), + Remove(bool), + Swap, + Reorder, + DidYouMean, + } + let mut suggestion_text = SuggestionText::None; + + let mut errors = errors.into_iter().peekable(); + while let Some(error) = errors.next() { + match error { + Error::Invalid(provided_idx, expected_idx, compatibility) => { + let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; + let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; + if let Compatibility::Incompatible(error) = &compatibility { + let cause = &self.misc(provided_span); + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + if let Some(e) = error { + self.note_type_err( + &mut err, + &trace.cause, + None, + Some(trace.values), + e, + false, + true, + ); + } + } - // Okay, now that we've emitted the special errors separately, we - // are only left missing/extra/swapped and mismatched arguments, both - // can be collated pretty easily if needed. - - // Next special case: if there is only one "Incompatible" error, just emit that - if errors.len() == 1 { - if let Some(Error::Invalid( - input_idx, - arg_idx, - Compatibility::Incompatible(Some(error)), - )) = errors.iter().next() - { - let expected_ty = expected_input_tys[*arg_idx]; - let provided_ty = final_arg_types[*input_idx] - .map(|ty| ty.0) - .unwrap_or_else(|| tcx.ty_error()); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let provided_ty = self.resolve_vars_if_possible(provided_ty); - let cause = &self.misc(provided_args[*input_idx].span); - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - let mut err = self.report_and_explain_type_error(trace, error); self.emit_coerce_suggestions( &mut err, - &provided_args[*input_idx], + &provided_args[provided_idx], provided_ty, - final_arg_types[*input_idx] - .map(|ty| ty.1) - .unwrap_or_else(|| tcx.ty_error()), + Expectation::rvalue_hint(self, expected_ty) + .only_has_type(self) + .unwrap_or(formal_ty), None, None, ); - err.span_label( - full_call_span, - format!("arguments to this {} are incorrect", call_name), - ); - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - err.emit(); - break 'errors; } - } - - let mut err = if minimum_input_count == provided_arg_count { - struct_span_err!( - tcx.sess, - full_call_span, - E0308, - "arguments to this {} are incorrect", - call_name, - ) - } else { - tcx.sess.struct_span_err_with_code( - full_call_span, - &format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(minimum_input_count, "argument"), - potentially_plural_count(provided_arg_count, "argument"), - if provided_arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(err_code.to_owned()), - ) - }; - - // As we encounter issues, keep track of what we want to provide for the suggestion - let mut labels = vec![]; - // If there is a single error, we give a specific suggestion; otherwise, we change to - // "did you mean" with the suggested function call - enum SuggestionText { - None, - Provide(bool), - Remove(bool), - Swap, - Reorder, - DidYouMean, - } - let mut suggestion_text = SuggestionText::None; - - let mut errors = errors.into_iter().peekable(); - while let Some(error) = errors.next() { - match error { - Error::Invalid(input_idx, arg_idx, compatibility) => { - let expected_ty = expected_input_tys[arg_idx]; - let provided_ty = final_arg_types[input_idx] - .map(|ty| ty.0) - .unwrap_or_else(|| tcx.ty_error()); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let provided_ty = self.resolve_vars_if_possible(provided_ty); - if let Compatibility::Incompatible(error) = &compatibility { - let cause = &self.misc(provided_args[input_idx].span); - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - if let Some(e) = error { - self.note_type_err( - &mut err, - &trace.cause, - None, - Some(trace.values), - e, - false, - true, - ); - } + Error::Extra(arg_idx) => { + let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; + let provided_ty_name = if !has_error_or_infer([provided_ty]) { + // FIXME: not suggestable, use something else + format!(" of type `{}`", provided_ty) + } else { + "".to_string() + }; + labels + .push((provided_span, format!("argument{} unexpected", provided_ty_name))); + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Remove(false), + SuggestionText::Remove(_) => SuggestionText::Remove(true), + _ => SuggestionText::DidYouMean, + }; + } + Error::Missing(expected_idx) => { + // If there are multiple missing arguments adjacent to each other, + // then we can provide a single error. + + let mut missing_idxs = vec![expected_idx]; + while let Some(e) = errors.next_if(|e| { + matches!(e, Error::Missing(next_expected_idx) + if *next_expected_idx == *missing_idxs.last().unwrap() + 1) + }) { + match e { + Error::Missing(expected_idx) => missing_idxs.push(expected_idx), + _ => unreachable!(), } - - self.emit_coerce_suggestions( - &mut err, - &provided_args[input_idx], - provided_ty, - // FIXME(compiler-errors): expected_ty? - final_arg_types[input_idx] - .map(|ty| ty.1) - .unwrap_or_else(|| tcx.ty_error()), - None, - None, - ); } - Error::Extra(arg_idx) => { - let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] { - if ty.references_error() || ty.has_infer_types() { - "".into() + + // NOTE: Because we might be re-arranging arguments, might have extra + // arguments, etc. it's hard to *really* know where we should provide + // this error label, so as a heuristic, we point to the provided arg, or + // to the call if the missing inputs pass the provided args. + match &missing_idxs[..] { + &[expected_idx] => { + let (_, input_ty) = formal_and_expected_inputs[expected_idx]; + let span = if let Some((_, arg_span)) = + provided_arg_tys.get(expected_idx.to_provided_idx()) + { + *arg_span } else { - format!(" of type `{}`", ty) - } - } else { - "".into() - }; - labels.push(( - provided_args[arg_idx].span, - format!("argument{} unexpected", arg_type), - )); - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Remove(false), - SuggestionText::Remove(_) => SuggestionText::Remove(true), - _ => SuggestionText::DidYouMean, - }; - } - Error::Missing(input_idx) => { - // If there are multiple missing arguments adjacent to each other, - // then we can provide a single error. - - let mut missing_idxs = vec![input_idx]; - while let Some(e) = errors.next_if(|e| matches!(e, Error::Missing(input_idx) if *input_idx == (missing_idxs.last().unwrap() + 1))) { - match e { - Error::Missing(input_idx) => missing_idxs.push(input_idx), - _ => unreachable!(), - } + args_span + }; + let rendered = if !has_error_or_infer([input_ty]) { + format!(" of type `{}`", input_ty) + } else { + "".to_string() + }; + labels.push((span, format!("an argument{} is missing", rendered))); + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Provide(false), + SuggestionText::Provide(_) => SuggestionText::Provide(true), + _ => SuggestionText::DidYouMean, + }; } - - // NOTE: Because we might be re-arranging arguments, might have extra - // arguments, etc. it's hard to *really* know where we should provide - // this error label, so as a heuristic, we point to the provided arg, or - // to the call if the missing inputs pass the provided args. - match &missing_idxs[..] { - &[input_idx] => { - let expected_ty = expected_input_tys[input_idx]; - let input_ty = self.resolve_vars_if_possible(expected_ty); - let span = if input_idx < provided_arg_count { - let arg_span = provided_args[input_idx].span; - Span::new(arg_span.lo(), arg_span.hi(), arg_span.ctxt(), None) - } else { - args_span - }; - let arg_type = - if input_ty.references_error() || input_ty.has_infer_types() { - "".into() - } else { - format!(" of type `{}`", input_ty) - }; - labels.push((span, format!("an argument{} is missing", arg_type))); - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Provide(false), - SuggestionText::Provide(_) => SuggestionText::Provide(true), - _ => SuggestionText::DidYouMean, - }; - } - &[first_idx, second_idx] => { - let first_input_ty = - self.resolve_vars_if_possible(expected_input_tys[first_idx]); - let second_input_ty = - self.resolve_vars_if_possible(expected_input_tys[second_idx]); - - let span = if second_idx < provided_arg_count { - let first_arg_span = provided_args[first_idx].span; - let second_arg_span = provided_args[second_idx].span; - Span::new( - first_arg_span.lo(), - second_arg_span.hi(), - first_arg_span.ctxt(), - None, - ) - } else { - args_span - }; - let any_unnameable = false - || first_input_ty.references_error() - || first_input_ty.has_infer_types() - || second_input_ty.references_error() - || second_input_ty.has_infer_types(); - let arg_type = if any_unnameable { - "".into() - } else { + &[first_idx, second_idx] => { + let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; + let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; + let span = if let (Some((_, first_span)), Some((_, second_span))) = ( + provided_arg_tys.get(first_idx.to_provided_idx()), + provided_arg_tys.get(second_idx.to_provided_idx()), + ) { + first_span.to(*second_span) + } else { + args_span + }; + let rendered = + if !has_error_or_infer([first_expected_ty, second_expected_ty]) { format!( " of type `{}` and `{}`", - first_input_ty, second_input_ty - ) - }; - labels - .push((span, format!("two arguments{} are missing", arg_type))); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - &[first_idx, second_idx, third_idx] => { - let first_input_ty = - self.resolve_vars_if_possible(expected_input_tys[first_idx]); - let second_input_ty = - self.resolve_vars_if_possible(expected_input_tys[second_idx]); - let third_input_ty = - self.resolve_vars_if_possible(expected_input_tys[third_idx]); - let span = if third_idx < provided_arg_count { - let first_arg_span = provided_args[first_idx].span; - let third_arg_span = provided_args[third_idx].span; - Span::new( - first_arg_span.lo(), - third_arg_span.hi(), - first_arg_span.ctxt(), - None, + first_expected_ty, second_expected_ty ) } else { - args_span + "".to_string() }; - let any_unnameable = false - || first_input_ty.references_error() - || first_input_ty.has_infer_types() - || second_input_ty.references_error() - || second_input_ty.has_infer_types() - || third_input_ty.references_error() - || third_input_ty.has_infer_types(); - let arg_type = if any_unnameable { - "".into() - } else { - format!( - " of type `{}`, `{}`, and `{}`", - first_input_ty, second_input_ty, third_input_ty - ) - }; - labels.push(( - span, - format!("three arguments{} are missing", arg_type), - )); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - missing_idxs => { - let first_idx = *missing_idxs.first().unwrap(); - let last_idx = *missing_idxs.last().unwrap(); - // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. - // It's hard to *really* know where we should provide this error label, so this is a - // decent heuristic - let span = if last_idx < provided_arg_count { - let first_arg_span = provided_args[first_idx].span; - let last_arg_span = provided_args[last_idx].span; - Span::new( - first_arg_span.lo(), - last_arg_span.hi(), - first_arg_span.ctxt(), - None, - ) - } else { - // Otherwise just label the whole function - args_span - }; - labels.push((span, format!("multiple arguments are missing"))); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } + labels.push((span, format!("two arguments{} are missing", rendered))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; } - } - Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx) => { - let first_span = provided_args[input_idx].span; - let second_span = provided_args[other_input_idx].span; - - let first_expected_ty = - self.resolve_vars_if_possible(expected_input_tys[arg_idx]); - let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] { - format!(", found `{}`", ty) - } else { - String::new() - }; - labels.push(( - first_span, - format!("expected `{}`{}", first_expected_ty, first_provided_ty), - )); - let other_expected_ty = - self.resolve_vars_if_possible(expected_input_tys[other_arg_idx]); - let other_provided_ty = - if let Some((ty, _)) = final_arg_types[other_input_idx] { - format!(", found `{}`", ty) + &[first_idx, second_idx, third_idx] => { + let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; + let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; + let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; + let span = if let (Some((_, first_span)), Some((_, third_span))) = ( + provided_arg_tys.get(first_idx.to_provided_idx()), + provided_arg_tys.get(third_idx.to_provided_idx()), + ) { + first_span.to(*third_span) } else { - String::new() + args_span }; - labels.push(( - second_span, - format!("expected `{}`{}", other_expected_ty, other_provided_ty), - )); - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Swap, - _ => SuggestionText::DidYouMean, - }; - } - Error::Permutation(args) => { - for (dst_arg, dest_input) in args { - let expected_ty = - self.resolve_vars_if_possible(expected_input_tys[dst_arg]); - let provided_ty = if let Some((ty, _)) = final_arg_types[dest_input] { - format!(", found `{}`", ty) + let rendered = if !has_error_or_infer([ + first_expected_ty, + second_expected_ty, + third_expected_ty, + ]) { + format!( + " of type `{}`, `{}`, and `{}`", + first_expected_ty, second_expected_ty, third_expected_ty + ) } else { - String::new() + "".to_string() + }; + labels.push((span, format!("three arguments{} are missing", rendered))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; + } + missing_idxs => { + let first_idx = *missing_idxs.first().unwrap(); + let last_idx = *missing_idxs.last().unwrap(); + // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. + // It's hard to *really* know where we should provide this error label, so this is a + // decent heuristic + let span = if let (Some((_, first_span)), Some((_, last_span))) = ( + provided_arg_tys.get(first_idx.to_provided_idx()), + provided_arg_tys.get(last_idx.to_provided_idx()), + ) { + first_span.to(*last_span) + } else { + args_span + }; + labels.push((span, format!("multiple arguments are missing"))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, }; - labels.push(( - provided_args[dest_input].span, - format!("expected `{}`{}", expected_ty, provided_ty), - )); } - - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Reorder, - _ => SuggestionText::DidYouMean, - }; } } - } - - // If we have less than 5 things to say, it would be useful to call out exactly what's wrong - if labels.len() <= 5 { - for (span, label) in labels { - err.span_label(span, label); - } - } - - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - - // And add a suggestion block for all of the parameters - let suggestion_text = match suggestion_text { - SuggestionText::None => None, - SuggestionText::Provide(plural) => { - Some(format!("provide the argument{}", if plural { "s" } else { "" })) - } - SuggestionText::Remove(plural) => { - Some(format!("remove the extra argument{}", if plural { "s" } else { "" })) - } - SuggestionText::Swap => Some("swap these arguments".to_string()), - SuggestionText::Reorder => Some("reorder these arguments".to_string()), - SuggestionText::DidYouMean => Some("did you mean".to_string()), - }; - if let Some(suggestion_text) = suggestion_text { - let source_map = self.sess().source_map(); - let mut suggestion = format!( - "{}(", - source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| String::new()) - ); - for (arg_index, input_idx) in matched_inputs.iter().enumerate() { - let suggestion_text = if let Some(input_idx) = input_idx { - let arg_span = provided_args[*input_idx].span.source_callsite(); - let arg_text = source_map.span_to_snippet(arg_span).unwrap(); - arg_text + Error::Swap( + first_provided_idx, + second_provided_idx, + first_expected_idx, + second_expected_idx, + ) => { + let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; + let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; + let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { + format!(", found `{}`", first_provided_ty) } else { - // Propose a placeholder of the correct type - let expected_ty = expected_input_tys[arg_index]; - let input_ty = self.resolve_vars_if_possible(expected_ty); - if input_ty.is_unit() { - "()".to_string() - } else if !input_ty.is_ty_var() { - format!("/* {} */", input_ty) - } else { - "/* value */".to_string() - } + String::new() + }; + labels.push(( + first_span, + format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), + )); + + let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; + let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; + let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { + format!(", found `{}`", second_provided_ty) + } else { + String::new() + }; + labels.push(( + second_span, + format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), + )); + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Swap, + _ => SuggestionText::DidYouMean, }; - suggestion += &suggestion_text; - if arg_index < minimum_input_count - 1 { - suggestion += ", "; + } + Error::Permutation(args) => { + for (dst_arg, dest_input) in args { + let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; + let (provided_ty, provided_span) = provided_arg_tys[dest_input]; + let provided_ty_name = if !has_error_or_infer([provided_ty]) { + format!(", found `{}`", provided_ty) + } else { + String::new() + }; + labels.push(( + provided_span, + format!("expected `{}`{}", expected_ty, provided_ty_name), + )); } + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Reorder, + _ => SuggestionText::DidYouMean, + }; } - suggestion += ")"; - err.span_suggestion_verbose( - error_span, - &suggestion_text, - suggestion, - Applicability::HasPlaceholders, - ); } - err.emit(); } - for arg in provided_args.iter().skip(minimum_input_count) { - let arg_ty = self.check_expr(&arg); + // If we have less than 5 things to say, it would be useful to call out exactly what's wrong + if labels.len() <= 5 { + for (span, label) in labels { + err.span_label(span, label); + } + } - // If the function is c-style variadic, we skipped a bunch of arguments - // so we need to check those, and write out the types - // Ideally this would be folded into the above, for uniform style - // but c-variadic is already a corner case - if c_variadic { - fn variadic_error<'tcx>( - sess: &'tcx Session, - span: Span, - ty: Ty<'tcx>, - cast_ty: &str, - ) { - use crate::structured_errors::MissingCastForVariadicArg; + // Call out where the function is defined + self.label_fn_like(&mut err, fn_def_id, callee_ty); - MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); + // And add a suggestion block for all of the parameters + let suggestion_text = match suggestion_text { + SuggestionText::None => None, + SuggestionText::Provide(plural) => { + Some(format!("provide the argument{}", if plural { "s" } else { "" })) + } + SuggestionText::Remove(plural) => { + Some(format!("remove the extra argument{}", if plural { "s" } else { "" })) + } + SuggestionText::Swap => Some("swap these arguments".to_string()), + SuggestionText::Reorder => Some("reorder these arguments".to_string()), + SuggestionText::DidYouMean => Some("did you mean".to_string()), + }; + if let Some(suggestion_text) = suggestion_text { + let source_map = self.sess().source_map(); + let mut suggestion = format!( + "{}(", + source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| fn_def_id + .map_or("".to_string(), |fn_def_id| tcx.item_name(fn_def_id).to_string())) + ); + let mut needs_comma = false; + for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { + if needs_comma { + suggestion += ", "; + } else { + needs_comma = true; } - - // There are a few types which get autopromoted when passed via varargs - // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind() { - ty::Float(ty::FloatTy::F32) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); - } - ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); - } - ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); - } - ty::FnDef(..) => { - let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(ptr_ty); - variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + let suggestion_text = if let Some(provided_idx) = provided_idx + && let (_, provided_span) = provided_arg_tys[*provided_idx] + && let Ok(arg_text) = + source_map.span_to_snippet(provided_span.source_callsite()) + { + arg_text + } else { + // Propose a placeholder of the correct type + let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; + if expected_ty.is_unit() { + "()".to_string() + } else if expected_ty.is_suggestable(tcx) { + format!("/* {} */", expected_ty) + } else { + "/* value */".to_string() } - _ => {} - } + }; + suggestion += &suggestion_text; } + suggestion += ")"; + err.span_suggestion_verbose( + error_span, + &suggestion_text, + suggestion, + Applicability::HasPlaceholders, + ); } - } - - fn suggested_tuple_wrap( - &self, - expected_input_tys: &[Ty<'tcx>], - provided_args: &'tcx [hir::Expr<'tcx>], - ) -> TupleMatchFound { - // Only handle the case where we expect only one tuple arg - let [expected_arg_type] = expected_input_tys[..] else { return TupleMatchFound::None }; - let &ty::Tuple(expected_types) = self.resolve_vars_if_possible(expected_arg_type).kind() - else { return TupleMatchFound::None }; - - // First check that there are the same number of types. - if expected_types.len() != provided_args.len() { - return TupleMatchFound::None; - } - - let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect(); - let all_match = iter::zip(expected_types, supplied_types) - .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok()); - - if !all_match { - return TupleMatchFound::None; - } - match provided_args { - [] => TupleMatchFound::None, - [_] => TupleMatchFound::Single, - [first, .., last] => { - TupleMatchFound::Multiple(first.span.shrink_to_lo(), last.span.shrink_to_hi()) - } - } + err.emit(); } // AST fragment checking @@ -1204,6 +1232,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty); + + if let Some(blk) = decl.els { + let previous_diverges = self.diverges.get(); + let else_ty = self.check_block_with_expected(blk, NoExpectation); + let cause = self.cause(blk.span, ObligationCauseCode::LetElse); + if let Some(mut err) = + self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + { + err.emit(); + } + self.diverges.set(previous_diverges); + } } /// Type check a `let` statement. @@ -1225,8 +1265,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_has_errors = self.has_errors.replace(false); match stmt.kind { - hir::StmtKind::Local(ref l) => { - self.check_decl_local(&l); + hir::StmtKind::Local(l) => { + self.check_decl_local(l); } // Ignore for now. hir::StmtKind::Item(_) => {} @@ -1599,10 +1639,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn point_at_arg_instead_of_call_if_possible( &self, errors: &mut Vec<traits::FulfillmentError<'tcx>>, - final_arg_types: &[Option<(Ty<'tcx>, Ty<'tcx>)>], expr: &'tcx hir::Expr<'tcx>, call_sp: Span, args: &'tcx [hir::Expr<'tcx>], + expected_tys: &[Ty<'tcx>], ) { // We *do not* do this for desugared call spans to keep good diagnostics when involving // the `?` operator. @@ -1610,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - for error in errors { + 'outer: for error in errors { // Only if the cause is somewhere inside the expression we want try to point at arg. // Otherwise, it means that the cause is somewhere else and we should not change // anything because we can break the correct span. @@ -1635,39 +1675,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result_code, code) = (code, parent); } } - let self_: ty::subst::GenericArg<'_> = match unpeel_to_top(error.obligation.cause.code()) { - ObligationCauseCode::BuiltinDerivedObligation(code) | - ObligationCauseCode::DerivedObligation(code) => { - code.parent_trait_pred.self_ty().skip_binder().into() - } - ObligationCauseCode::ImplDerivedObligation(code) => { - code.derived.parent_trait_pred.self_ty().skip_binder().into() - } - _ if let ty::PredicateKind::Trait(predicate) = - error.obligation.predicate.kind().skip_binder() => { + let self_: ty::subst::GenericArg<'_> = + match unpeel_to_top(error.obligation.cause.code()) { + ObligationCauseCode::BuiltinDerivedObligation(code) + | ObligationCauseCode::DerivedObligation(code) => { + code.parent_trait_pred.self_ty().skip_binder().into() + } + ObligationCauseCode::ImplDerivedObligation(code) => { + code.derived.parent_trait_pred.self_ty().skip_binder().into() + } + _ if let ty::PredicateKind::Trait(predicate) = + error.obligation.predicate.kind().skip_binder() => + { predicate.self_ty().into() } - _ => continue, - }; + _ => continue, + }; let self_ = self.resolve_vars_if_possible(self_); + let ty_matches_self = |ty: Ty<'tcx>| ty.walk().any(|arg| arg == self_); + + let typeck_results = self.typeck_results.borrow(); + + for (idx, arg) in args.iter().enumerate() { + // Don't adjust the span if we already have a more precise span + // within one of the args. + if arg.span.contains(error.obligation.cause.span) { + let references_arg = + typeck_results.expr_ty_opt(arg).map_or(false, &ty_matches_self) + || expected_tys.get(idx).copied().map_or(false, &ty_matches_self); + if references_arg && !arg.span.from_expansion() { + error.obligation.cause.map_code(|parent_code| { + ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id: args[idx].hir_id, + call_hir_id: expr.hir_id, + parent_code, + } + }) + } + continue 'outer; + } + } // Collect the argument position for all arguments that could have caused this // `FulfillmentError`. - let mut referenced_in = final_arg_types - .iter() + let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args) .enumerate() - .filter_map(|(i, arg)| match arg { - Some((checked_ty, coerce_ty)) => Some([(i, *checked_ty), (i, *coerce_ty)]), - _ => None, + .flat_map(|(idx, (expected_ty, arg))| { + if let Some(arg_ty) = typeck_results.expr_ty_opt(arg) { + vec![(idx, arg_ty), (idx, *expected_ty)] + } else { + vec![] + } }) - .flatten() - .flat_map(|(i, ty)| { + .filter_map(|(i, ty)| { let ty = self.resolve_vars_if_possible(ty); // We walk the argument type because the argument's type could have // been `Option<T>`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == self_) { Some(i) } else { None } + if ty_matches_self(ty) { Some(i) } else { None } }) - .collect::<Vec<usize>>(); + .collect(); // Both checked and coerced types could have matched, thus we need to remove // duplicates. @@ -1676,18 +1742,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { referenced_in.sort_unstable(); referenced_in.dedup(); - if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { + if let &[idx] = &referenced_in[..] { // Do not point at the inside of a macro. // That would often result in poor error messages. - if args[ref_in].span.from_expansion() { - return; + if args[idx].span.from_expansion() { + continue; } // We make sure that only *one* argument matches the obligation failure // and we assign the obligation's span to its expression's. - error.obligation.cause.span = args[ref_in].span; + error.obligation.cause.span = args[idx].span; error.obligation.cause.map_code(|parent_code| { ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id: args[ref_in].hir_id, + arg_hir_id: args[idx].hir_id, call_hir_id: expr.hir_id, parent_code, } @@ -1746,47 +1812,126 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } -} -fn label_fn_like<'tcx>( - tcx: TyCtxt<'tcx>, - err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, - def_id: Option<DefId>, -) { - let Some(def_id) = def_id else { - return; - }; - - if let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .flat_map(|id| tcx.hir().body(id).params); - - for param in params { - spans.push_span_label(param.span, String::new()); + fn label_fn_like( + &self, + err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, + callable_def_id: Option<DefId>, + callee_ty: Option<Ty<'tcx>>, + ) { + let Some(mut def_id) = callable_def_id else { + return; + }; + + if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) + // Possibly points at either impl or trait item, so try to get it + // to point to trait item, then get the parent. + // This parent might be an impl in the case of an inherent function, + // but the next check will fail. + && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) + && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) + // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" + && let Some(call_kind) = ty::ClosureKind::from_def_id(self.tcx, maybe_trait_def_id) + && let Some(callee_ty) = callee_ty + { + let callee_ty = callee_ty.peel_refs(); + match *callee_ty.kind() { + ty::Param(param) => { + let param = + self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx); + if param.kind.is_synthetic() { + // if it's `impl Fn() -> ..` then just fall down to the def-id based logic + def_id = param.def_id; + } else { + // Otherwise, find the predicate that makes this generic callable, + // and point at that. + let instantiated = self + .tcx + .explicit_predicates_of(self.body_id.owner) + .instantiate_identity(self.tcx); + // FIXME(compiler-errors): This could be problematic if something has two + // fn-like predicates with different args, but callable types really never + // do that, so it's OK. + for (predicate, span) in + std::iter::zip(instantiated.predicates, instantiated.spans) + { + if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder() + && pred.self_ty().peel_refs() == callee_ty + && ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some() + { + err.span_note(span, "callable defined here"); + return; + } + } + } + } + ty::Opaque(new_def_id, _) + | ty::Closure(new_def_id, _) + | ty::FnDef(new_def_id, _) => { + def_id = new_def_id; + } + _ => { + // Look for a user-provided impl of a `Fn` trait, and point to it. + let new_def_id = self.probe(|_| { + let trait_ref = ty::TraitRef::new( + call_kind.to_def_id(self.tcx), + self.tcx.mk_substs([ + ty::GenericArg::from(callee_ty), + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: rustc_span::DUMMY_SP, + }) + .into(), + ].into_iter()), + ); + let obligation = traits::Obligation::new( + traits::ObligationCause::dummy(), + self.param_env, + ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }), + ); + match SelectionContext::new(&self).select(&obligation) { + Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { + Some(impl_source.impl_def_id) + } + _ => None + } + }); + if let Some(new_def_id) = new_def_id { + def_id = new_def_id; + } else { + return; + } + } + } } - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } else { - match tcx.hir().get_if_local(def_id) { - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure { fn_decl_span, .. }, - .. - })) => { - let spans: MultiSpan = (*fn_decl_span).into(); + if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { + let mut spans: MultiSpan = def_span.into(); - // Note: We don't point to param spans here because they overlap - // with the closure span itself + let params = self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.body_id()) + .into_iter() + .flat_map(|id| self.tcx.hir().body(id).params); - err.span_note(spans, "closure defined here"); + for param in params { + spans.push_span_label(param.span, ""); } - _ => {} + + let def_kind = self.tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } else { + let def_kind = self.tcx.def_kind(def_id); + err.span_note( + self.tcx.def_span(def_id), + &format!("{} defined here", def_kind.descr(def_id)), + ); } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 8b680a3d042da..05bcc710e1625 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -15,8 +15,8 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::Ident; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 7195da863db48..80feac184125c 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -13,14 +13,11 @@ use rustc_hir::{ use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use std::iter; - impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) { err.span_suggestion_short( @@ -185,79 +182,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) { if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { - let sp = self.sess().source_map().guess_head_span(sp); - err.span_label(sp, &format!("{} defined here", found)); + err.span_label(sp, format!("{found} defined here")); } } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { - let is_struct_pat_shorthand_field = - self.maybe_get_struct_pattern_shorthand_field(expr).is_some(); let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); if !methods.is_empty() { - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) - .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.name); - if receiver.ends_with(&method_call) { - None // do not suggest code that is already there (#53348) - } else { - let method_call_list = [".to_vec()", ".to_string()"]; - let mut sugg = if receiver.ends_with(".clone()") - && method_call_list.contains(&method_call.as_str()) - { - let max_len = receiver.rfind('.').unwrap(); - vec![( - expr.span, - format!("{}{}", &receiver[..max_len], method_call), - )] - } else { - if expr.precedence().order() - < ExprPrecedence::MethodCall.order() - { - vec![ - (expr.span.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), format!("){}", method_call)), - ] - } else { - vec![(expr.span.shrink_to_hi(), method_call)] - } - }; - if is_struct_pat_shorthand_field { - sugg.insert( - 0, - (expr.span.shrink_to_lo(), format!("{}: ", receiver)), - ); - } - Some(sugg) - } - }) - .peekable(); - if suggestions.peek().is_some() { - err.multipart_suggestions( - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); - } + let mut suggestions = methods.iter() + .filter_map(|conversion_method| { + let receiver_method_ident = expr.method_ident(); + if let Some(method_ident) = receiver_method_ident + && method_ident.name == conversion_method.name + { + return None // do not suggest code that is already there (#53348) + } + + let method_call_list = [sym::to_vec, sym::to_string]; + let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind + && receiver_method.ident.name == sym::clone + && method_call_list.contains(&conversion_method.name) + // If receiver is `.clone()` and found type has one of those methods, + // we guess that the user wants to convert from a slice type (`&[]` or `&str`) + // to an owned type (`Vec` or `String`). These conversions clone internally, + // so we remove the user's `clone` call. + { + vec![( + receiver_method.ident.span, + conversion_method.name.to_string() + )] + } else if expr.precedence().order() + < ExprPrecedence::MethodCall.order() + { + vec![ + (expr.span.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), + ] + } else { + vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] + }; + let struct_pat_shorthand_field = self.maybe_get_struct_pattern_shorthand_field(expr); + if let Some(name) = struct_pat_shorthand_field { + sugg.insert( + 0, + (expr.span.shrink_to_lo(), format!("{}: ", name)), + ); + } + Some(sugg) + }) + .peekable(); + if suggestions.peek().is_some() { + err.multipart_suggestions( + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); } - } else if found.to_string().starts_with("Option<") - && expected.to_string() == "Option<&str>" + } else if let ty::Adt(found_adt, found_substs) = found.kind() + && self.tcx.is_diagnostic_item(sym::Option, found_adt.did()) + && let ty::Adt(expected_adt, expected_substs) = expected.kind() + && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) + && let ty::Ref(_, inner_ty, _) = expected_substs.type_at(0).kind() + && inner_ty.is_str() { - if let ty::Adt(_def, subst) = found.kind() { - if subst.len() != 0 { - if let GenericArgKind::Type(ty) = subst[0].unpack() { - let peeled = ty.peel_refs().to_string(); - if peeled == "String" { - let ref_cnt = ty.to_string().len() - peeled.len(); - let result = format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)); - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - "try converting the passed type into a `&str`", - result, - Applicability::MaybeIncorrect, - ); - } - } - } + let ty = found_substs.type_at(0); + let mut peeled = ty; + let mut ref_cnt = 0; + while let ty::Ref(_, inner, _) = peeled.kind() { + peeled = *inner; + ref_cnt += 1; + } + if let ty::Adt(adt, _) = peeled.kind() + && self.tcx.is_diagnostic_item(sym::String, adt.did()) + { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + "try converting the passed type into a `&str`", + format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)), + Applicability::MaybeIncorrect, + ); } } } diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 576dc6f127cbd..8f34a970f6ff7 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -16,19 +16,20 @@ pub(super) struct Declaration<'a> { pub ty: Option<&'a hir::Ty<'a>>, pub span: Span, pub init: Option<&'a hir::Expr<'a>>, + pub els: Option<&'a hir::Block<'a>>, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { - let hir::Local { hir_id, pat, ty, span, init, .. } = *local; - Declaration { hir_id, pat, ty, span, init } + let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; + Declaration { hir_id, pat, ty, span, init, els } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { hir_id, pat, ty, span, init: Some(init) } + Declaration { hir_id, pat, ty, span, init: Some(init), els: None } } } @@ -101,7 +102,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add explicitly-declared locals. fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { self.declare(local.into()); - intravisit::walk_local(self, local); + intravisit::walk_local(self, local) } fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index f09c7f51f4714..d4f8001493c8b 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; -use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt}; +use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable}; use rustc_span::symbol::sym; use rustc_span::Span; use tracing::debug; @@ -69,7 +69,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.expr_and_pat_count, self.expr_count, source_span ); - if self.fcx.sess().opts.debugging_opts.drop_tracking + if self.fcx.sess().opts.unstable_opts.drop_tracking && self .drop_ranges .is_dropped_at(hir_id, yield_data.expr_and_pat_count) @@ -225,7 +225,7 @@ pub fn resolve_interior<'a, 'tcx>( // Note that each region slot in the types gets a new fresh late bound region, // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. - let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| { + let folded = fcx.tcx.fold_regions(erased, |_, current_depth| { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon(counter), @@ -376,6 +376,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr)); + let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr); + let may_need_drop = |ty: Ty<'tcx>| { + // Avoid ICEs in needs_drop. + let ty = self.fcx.resolve_vars_if_possible(ty); + let ty = self.fcx.tcx.erase_regions(ty); + if ty.needs_infer() { + return true; + } + ty.needs_drop(self.fcx.tcx, self.fcx.param_env) + }; + // Typically, the value produced by an expression is consumed by its parent in some way, // so we only have to check if the parent contains a yield (note that the parent may, for // example, store the value into a local variable, but then we already consider local @@ -384,7 +395,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // However, in the case of temporary values, we are going to store the value into a // temporary on the stack that is live for the current temporary scope and then return a // reference to it. That value may be live across the entire temporary scope. - let scope = if self.drop_ranges.is_borrowed_temporary(expr) { + // + // There's another subtlety: if the type has an observable drop, it must be dropped after + // the yield, even if it's not borrowed or referenced after the yield. Ideally this would + // *only* happen for types with observable drop, not all types which wrap them, but that + // doesn't match the behavior of MIR borrowck and causes ICEs. See the FIXME comment in + // src/test/ui/generator/drop-tracking-parent-expression.rs. + let scope = if self.drop_ranges.is_borrowed_temporary(expr) + || ty.map_or(true, |ty| { + let needs_drop = may_need_drop(ty); + debug!(?needs_drop, ?ty); + needs_drop + }) { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) } else { debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id)); @@ -398,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // If there are adjustments, then record the final type -- // this is the actual value that is being produced. - if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) { + if let Some(adjusted_ty) = ty { self.record(adjusted_ty, expr.hir_id, scope, Some(expr), expr.span); } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs index c2b4c478ba387..14b226d91cbf8 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs @@ -38,7 +38,7 @@ pub fn compute_drop_ranges<'a, 'tcx>( def_id: DefId, body: &'tcx Body<'tcx>, ) -> DropRanges { - if fcx.sess().opts.debugging_opts.drop_tracking { + if fcx.sess().opts.unstable_opts.drop_tracking { let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body); let typeck_results = &fcx.typeck_results.borrow(); @@ -109,7 +109,7 @@ rustc_index::newtype_index! { } /// Identifies a value whose drop state we need to track. -#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] +#[derive(PartialEq, Eq, Hash, Clone, Copy)] enum TrackedValue { /// Represents a named variable, such as a let binding, parameter, or upvar. /// @@ -121,6 +121,21 @@ enum TrackedValue { Temporary(HirId), } +impl Debug for TrackedValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + write!(f, "{}", tcx.hir().node_to_string(self.hir_id())) + } else { + match self { + Self::Variable(hir_id) => write!(f, "Variable({:?})", hir_id), + Self::Temporary(hir_id) => write!(f, "Temporary({:?})", hir_id), + } + } + }) + } +} + impl TrackedValue { fn hir_id(&self) -> HirId { match self { @@ -148,7 +163,7 @@ enum TrackedValueConversionError { /// Place projects are not currently supported. /// /// The reasoning around these is kind of subtle, so we choose to be more - /// conservative around these for now. There is not reason in theory we + /// conservative around these for now. There is no reason in theory we /// cannot support these, we just have not implemented it yet. PlaceProjectionsNotSupported, } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index dbc309b29ff11..da2db3f2e30ab 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -33,6 +33,9 @@ pub(super) fn build_control_flow_graph<'tcx>( intravisit::walk_body(&mut drop_range_visitor, body); drop_range_visitor.drop_ranges.process_deferred_edges(); + if let Some(filename) = &tcx.sess.opts.unstable_opts.dump_drop_tracking_cfg { + super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx); + } (drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries) } @@ -126,13 +129,14 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all /// expressions. This method consumes a little deeper into the expression when needed. fn consume_expr(&mut self, expr: &hir::Expr<'_>) { - debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index); + debug!("consuming expr {:?}, count={:?}", expr.kind, self.expr_index); let places = self .places .consumed .get(&expr.hir_id) .map_or(vec![], |places| places.iter().cloned().collect()); for place in places { + trace!(?place, "consuming place"); for_each_consumable(self.hir, place, |value| self.record_drop(value)); } } @@ -251,7 +255,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { | hir::Node::Ty(..) | hir::Node::TypeBinding(..) | hir::Node::TraitRef(..) - | hir::Node::Binding(..) | hir::Node::Pat(..) | hir::Node::Arm(..) | hir::Node::Local(..) diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs index 20aad7aedf775..c0a0bfe8e1c00 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs @@ -2,6 +2,7 @@ //! flow graph when needed for debugging. use rustc_graphviz as dot; +use rustc_middle::ty::TyCtxt; use super::{DropRangesBuilder, PostOrderId}; @@ -9,22 +10,35 @@ use super::{DropRangesBuilder, PostOrderId}; /// /// It is not normally called, but is kept around to easily add debugging /// code when needed. -#[allow(dead_code)] -pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) { - dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap(); +pub(super) fn write_graph_to_file( + drop_ranges: &DropRangesBuilder, + filename: &str, + tcx: TyCtxt<'_>, +) { + dot::render( + &DropRangesGraph { drop_ranges, tcx }, + &mut std::fs::File::create(filename).unwrap(), + ) + .unwrap(); } -impl<'a> dot::GraphWalk<'a> for DropRangesBuilder { +struct DropRangesGraph<'a, 'tcx> { + drop_ranges: &'a DropRangesBuilder, + tcx: TyCtxt<'tcx>, +} + +impl<'a> dot::GraphWalk<'a> for DropRangesGraph<'_, '_> { type Node = PostOrderId; type Edge = (PostOrderId, PostOrderId); fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> { - self.nodes.iter_enumerated().map(|(i, _)| i).collect() + self.drop_ranges.nodes.iter_enumerated().map(|(i, _)| i).collect() } fn edges(&'a self) -> dot::Edges<'a, Self::Edge> { - self.nodes + self.drop_ranges + .nodes .iter_enumerated() .flat_map(|(i, node)| { if node.successors.len() == 0 { @@ -45,7 +59,7 @@ impl<'a> dot::GraphWalk<'a> for DropRangesBuilder { } } -impl<'a> dot::Labeller<'a> for DropRangesBuilder { +impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> { type Node = PostOrderId; type Edge = (PostOrderId, PostOrderId); @@ -61,15 +75,15 @@ impl<'a> dot::Labeller<'a> for DropRangesBuilder { fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> { dot::LabelText::LabelStr( format!( - "{:?}, local_id: {}", - n, - self.post_order_map + "{n:?}: {}", + self.drop_ranges + .post_order_map .iter() .find(|(_hir_id, &post_order_id)| post_order_id == *n) - .map_or("<unknown>".into(), |(hir_id, _)| format!( - "{}", - hir_id.local_id.index() - )) + .map_or("<unknown>".into(), |(hir_id, _)| self + .tcx + .hir() + .node_to_string(*hir_id)) ) .into(), ) diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs index b22b791f629d7..67cc46f21f00b 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -75,6 +75,7 @@ impl<'tcx> ExprUseDelegate<'tcx> { if !self.places.consumed.contains_key(&consumer) { self.places.consumed.insert(consumer, <_>::default()); } + debug!(?consumer, ?target, "mark_consumed"); self.places.consumed.get_mut(&consumer).map(|places| places.insert(target)); } @@ -136,13 +137,16 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>, diag_expr_id: HirId, ) { - let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) { + let hir = self.tcx.hir(); + let parent = match hir.find_parent_node(place_with_id.hir_id) { Some(parent) => parent, None => place_with_id.hir_id, }; debug!( - "consume {:?}; diag_expr_id={:?}, using parent {:?}", - place_with_id, diag_expr_id, parent + "consume {:?}; diag_expr_id={}, using parent {}", + place_with_id, + hir.node_to_string(diag_expr_id), + hir.node_to_string(parent) ); place_with_id .try_into() diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 08a64d8e67364..4afbc00b37c73 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -8,6 +8,7 @@ use rustc_hir::HirIdMap; use rustc_infer::infer; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{self, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -102,7 +103,7 @@ impl<'tcx> InheritedBuilder<'tcx> { } impl<'a, 'tcx> Inherited<'a, 'tcx> { - pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { + fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { let tcx = infcx.tcx; let item_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = tcx.hir().maybe_body_owned_by(item_id); @@ -112,7 +113,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { maybe_typeck_results: infcx.in_progress_typeck_results, }, infcx, - fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)), + fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new_ignoring_regions(tcx)), locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index 469e6118575d2..0adf0d28aae10 100644 --- a/compiler/rustc_typeck/src/check/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -4,7 +4,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; -use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy}; +use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy}; use rustc_session::lint; use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::{Pointer, VariantIdx}; @@ -99,8 +99,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } + // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { - if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) { + // Type still may have region variables, but `Sized` does not depend + // on those, so just erase them before querying. + if self.tcx.erase_regions(ty).is_sized(self.tcx.at(DUMMY_SP), self.param_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -108,6 +111,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } false } +} + +pub struct InlineAsmCtxt<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + fcx: Option<&'a FnCtxt<'a, 'tcx>>, +} + +impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { + pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { + InlineAsmCtxt { tcx, fcx: None } + } + + pub fn new_in_fn(fcx: &'a FnCtxt<'a, 'tcx>) -> Self { + InlineAsmCtxt { tcx: fcx.tcx, fcx: Some(fcx) } + } fn check_asm_operand_type( &self, @@ -119,43 +137,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>, target_features: &FxHashSet<Symbol>, ) -> Option<InlineAsmType> { + let fcx = self.fcx.unwrap_or_else(|| span_bug!(expr.span, "asm operand for global asm")); // Check the type against the allowed types for inline asm. - let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); - let ty = self.resolve_vars_if_possible(ty); + let ty = fcx.typeck_results.borrow().expr_ty_adjusted(expr); + let ty = fcx.resolve_vars_if_possible(ty); let asm_ty_isize = match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, 64 => InlineAsmType::I64, _ => unreachable!(), }; + + // Expect types to be fully resolved, no const or type variables. + if ty.has_infer_types_or_consts() { + assert!(fcx.is_tainted_by_errors()); + return None; + } + let asm_ty = match *ty.kind() { // `!` is allowed for input but not for output (issue #87802) ty::Never if is_input => return None, ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), - // Somewhat of a hack: fallback in the presence of errors does not actually - // fall back to i32, but to ty::Error. For integer inference variables this - // means that they don't get any fallback and stay as `{integer}`. - // Since compilation can't succeed anyway, it's fine to use this to avoid printing - // "cannot use value of type `{integer}`", even though that would absolutely - // work due due i32 fallback if the current function had no other errors. - ty::Infer(InferTy::IntVar(_)) => { - assert!(self.is_tainted_by_errors()); - Some(InlineAsmType::I32) - } ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32), ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64), ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize), - ty::Infer(InferTy::FloatVar(_)) => { - assert!(self.is_tainted_by_errors()); - Some(InlineAsmType::F32) - } ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), ty::FnPtr(_) => Some(asm_ty_isize), - ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if self.is_thin_ptr_ty(ty) => { + ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if fcx.is_thin_ptr_ty(ty) => { Some(asm_ty_isize) } ty::Adt(adt, substs) if adt.repr().simd() => { @@ -191,6 +203,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, } } + ty::Infer(_) => unreachable!(), _ => None, }; let Some(asm_ty) = asm_ty else { @@ -204,14 +217,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - if ty.has_infer_types_or_consts() { - assert!(self.is_tainted_by_errors()); - return None; - } - // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { + if !fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, ty, DUMMY_SP) { let msg = "arguments for inline assembly must be copyable"; let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!("`{ty}` does not implement the Copy trait")); @@ -232,8 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = "incompatible types for asm inout argument"; let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg); - let in_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(in_expr); - let in_expr_ty = self.resolve_vars_if_possible(in_expr_ty); + let in_expr_ty = fcx.typeck_results.borrow().expr_ty_adjusted(in_expr); + let in_expr_ty = fcx.resolve_vars_if_possible(in_expr_ty); err.span_label(in_expr.span, &format!("type `{in_expr_ty}`")); err.span_label(expr.span, &format!("type `{ty}`")); err.note( diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 4061b7cae7c78..b14f3d6de4ef1 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -81,11 +81,25 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs); - debug!("all_substs={:?}", all_substs); + debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}"); // Create the final signature for the method, replacing late-bound regions. let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs); + // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that + // something which derefs to `Self` actually implements the trait and the caller + // wanted to make a static dispatch on it but forgot to import the trait. + // See test `src/test/ui/issue-35976.rs`. + // + // In that case, we'll error anyway, but we'll also re-run the search with all traits + // in scope, and if we find another method which can be used, we'll output an + // appropriate hint suggesting to import the trait. + let filler_substs = rcvr_substs + .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def)); + let illegal_sized_bound = self.predicates_require_illegal_sized_bound( + &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs), + ); + // Unify the (adjusted) self type with what the method expects. // // SUBTLE: if we want good error messages, because of "guessing" while matching @@ -106,16 +120,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); - // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that - // something which derefs to `Self` actually implements the trait and the caller - // wanted to make a static dispatch on it but forgot to import the trait. - // See test `src/test/ui/issue-35976.rs`. - // - // In that case, we'll error anyway, but we'll also re-run the search with all traits - // in scope, and if we find another method which can be used, we'll output an - // appropriate hint suggesting to import the trait. - let illegal_sized_bound = self.predicates_require_illegal_sized_bound(&method_predicates); - // Add any trait/regions obligations specified on the method's type parameters. // We won't add these if we encountered an illegal sized bound, so that we can use // a custom error in that case. @@ -501,7 +505,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the function type must also be well-formed (this is not // implied by the substs being well-formed because of inherent // impls and late-bound regions - see issue #28609). - self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation); + self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None)); } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 5ca822183556b..c09f63f1e8f11 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -10,7 +10,7 @@ mod suggest; pub use self::suggest::SelfSource; pub use self::MethodError::*; -use crate::check::FnCtxt; +use crate::check::{Expectation, FnCtxt}; use crate::ObligationCause; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; @@ -20,8 +20,10 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; +use rustc_middle::ty::{ + self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term, + ToPredicate, Ty, TypeVisitable, +}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -221,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // We probe again, taking all traits into account (not only those in scope). - let candidates = match self.lookup_probe( + let mut candidates = match self.lookup_probe( span, segment.ident, self_ty, @@ -243,6 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(), _ => Vec::new(), }; + candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id)); return Err(IllegalSizedBound(candidates, needs_mut, span)); } @@ -317,6 +320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, opt_input_type: Option<Ty<'tcx>>, opt_input_expr: Option<&'tcx hir::Expr<'tcx>>, + expected: Expectation<'tcx>, ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) { // Construct a trait-reference `self_ty : Trait<input_tys>` @@ -338,6 +342,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Construct an obligation let poly_trait_ref = ty::Binder::dummy(trait_ref); + let opt_output_ty = + expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty)); + let opt_output_assoc_item = self.tcx.associated_items(trait_def_id).find_by_name_and_kind( + self.tcx, + Ident::from_str("Output"), + AssocKind::Type, + trait_def_id, + ); + let output_pred = + opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| { + ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate { + projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id }, + term: Term::Ty(output_ty), + })) + .to_predicate(self.tcx) + }); + ( traits::Obligation::new( traits::ObligationCause::new( @@ -347,6 +368,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), + output_pred, }, ), self.param_env, @@ -396,6 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, opt_input_type: Option<Ty<'tcx>>, opt_input_expr: Option<&'tcx hir::Expr<'tcx>>, + expected: Expectation<'tcx>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { let (obligation, substs) = self.obligation_for_op_method( span, @@ -403,6 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, opt_input_type, opt_input_expr, + expected, ); self.construct_obligation_for_trait( span, @@ -504,6 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), + output_pred: None, }, ) } else { diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 87254b211d67b..416d33c7aa040 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -21,7 +21,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::lev_distance::{ @@ -711,7 +711,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = EarlyBinder(impl_ty).subst(self.tcx, impl_substs); + let impl_ty = impl_ty.subst(self.tcx, impl_substs); debug!("impl_ty: {:?}", impl_ty); @@ -1065,7 +1065,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let pick = self.pick_all_method(Some(&mut unstable_candidates)); // In this case unstable picking is done by `pick_method`. - if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable { + if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable { return pick; } @@ -1269,7 +1269,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self_ty: Ty<'tcx>, mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option<PickResult<'tcx>> { - if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable { + if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable { return self.pick_method_with_unstable(self_ty); } @@ -1809,9 +1809,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.erase_late_bound_regions(xform_fn_sig) } - /// Gets the type of an impl and generate substitutions with placeholders. - fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, SubstsRef<'tcx>) { - (self.tcx.type_of(impl_def_id), self.fresh_item_substs(impl_def_id)) + /// Gets the type of an impl and generate substitutions with inference vars. + fn impl_ty_and_substs( + &self, + impl_def_id: DefId, + ) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) { + (self.tcx.bound_type_of(impl_def_id), self.fresh_item_substs(impl_def_id)) } fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 8880049371e58..7f96e421a9ae3 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -17,8 +17,9 @@ use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::with_crate_prefix; use rustc_middle::ty::ToPolyTraitRef; -use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Symbol; use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span}; use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -121,11 +122,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) else { continue; }; - let note_span = self - .tcx - .hir() - .span_if_local(item.def_id) - .or_else(|| self.tcx.hir().span_if_local(impl_did)); + + let note_span = if item.def_id.is_local() { + Some(self.tcx.def_span(item.def_id)) + } else if impl_did.is_local() { + Some(self.tcx.def_span(impl_did)) + } else { + None + }; let impl_ty = self.tcx.at(span).type_of(impl_did); @@ -158,10 +162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(note_span) = note_span { // We have a span pointing to the method. Show note with snippet. - err.span_note( - self.tcx.sess.source_map().guess_head_span(note_span), - ¬e_str, - ); + err.span_note(note_span, ¬e_str); } else { err.note(¬e_str); } @@ -197,11 +198,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } CandidateSource::Trait(trait_did) => { let Some(item) = self.associated_value(trait_did, item_name) else { continue }; - let item_span = self - .tcx - .sess - .source_map() - .guess_head_span(self.tcx.def_span(item.def_id)); + let item_span = self.tcx.def_span(item.def_id); let idx = if sources.len() > 1 { let msg = &format!( "candidate #{} is defined in the trait `{}`", @@ -346,19 +343,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if let Some(def) = actual.ty_adt_def() { - if let Some(full_sp) = tcx.hir().span_if_local(def.did()) { - let def_sp = tcx.sess.source_map().guess_head_span(full_sp); - err.span_label( - def_sp, - format!( - "{} `{}` not found {}", - item_kind, - item_name, - if def.is_enum() && !is_method { "here" } else { "for this" } - ), - ); + let ty_span = match actual.kind() { + ty::Param(param_type) => { + let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); + let type_param = generics.type_param(param_type, self.tcx); + Some(self.tcx.def_span(type_param.def_id)) } + ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())), + _ => None, + }; + + if let Some(span) = ty_span { + err.span_label( + span, + format!( + "{item_kind} `{item_name}` not found for this {}", + actual.prefix_string(self.tcx) + ), + ); } if self.is_fn_ty(rcvr_ty, span) { @@ -464,9 +466,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement")); } } else if !unsatisfied_predicates.is_empty() { - let def_span = |def_id| { - self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)) - }; let mut type_params = FxHashMap::default(); // Pick out the list of unimplemented traits on the receiver. @@ -557,22 +556,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); match &self_ty.kind() { // Point at the type that couldn't satisfy the bound. - ty::Adt(def, _) => bound_spans.push((def_span(def.did()), msg)), + ty::Adt(def, _) => { + bound_spans.push((self.tcx.def_span(def.did()), msg)) + } // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::Trait(tr) => { - bound_spans.push((def_span(tr.def_id), msg.clone())) - } + ty::ExistentialPredicate::Trait(tr) => bound_spans + .push((self.tcx.def_span(tr.def_id), msg.clone())), ty::ExistentialPredicate::Projection(_) | ty::ExistentialPredicate::AutoTrait(_) => {} } } } // Point at the closure that couldn't satisfy the bound. - ty::Closure(def_id, _) => bound_spans - .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))), + ty::Closure(def_id, _) => bound_spans.push(( + tcx.def_span(*def_id), + format!("doesn't satisfy `{}`", quiet), + )), _ => {} } }; @@ -618,12 +620,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find all the requirements that come from a local `impl` block. let mut skip_list: FxHashSet<_> = Default::default(); let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default(); - for (data, p, parent_p, impl_def_id, cause_span) in unsatisfied_predicates + for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates .iter() .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c))) .filter_map(|(p, parent, c)| match c.code() { ObligationCauseCode::ImplDerivedObligation(ref data) => { - Some((&data.derived, p, parent, data.impl_def_id, data.span)) + Some((&data.derived, p, parent, data.impl_def_id, data)) } _ => None, }) @@ -631,7 +633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_trait_ref = data.parent_trait_pred; let path = parent_trait_ref.print_modifiers_and_trait_path(); let tr_self_ty = parent_trait_ref.skip_binder().self_ty(); - let unsatisfied_msg = "unsatisfied trait bound introduced here".to_string(); + let unsatisfied_msg = "unsatisfied trait bound introduced here"; let derive_msg = "unsatisfied trait bound introduced in this `derive` macro"; match self.tcx.hir().get_if_local(impl_def_id) { @@ -648,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let span = ident.span.ctxt().outer_expn_data().call_site; let mut spans: MultiSpan = span.into(); - spans.push_span_label(span, derive_msg.to_string()); + spans.push_span_label(span, derive_msg); let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); } @@ -671,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let span = self_ty.span.ctxt().outer_expn_data().call_site; let mut spans: MultiSpan = span.into(); - spans.push_span_label(span, derive_msg.to_string()); + spans.push_span_label(span, derive_msg); let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); } @@ -692,21 +694,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let _ = format_pred(*pred); } skip_list.insert(p); - let mut spans = if cause_span != *item_span { - let mut spans: MultiSpan = cause_span.into(); - spans.push_span_label(cause_span, unsatisfied_msg); + let mut spans = if cause.span != *item_span { + let mut spans: MultiSpan = cause.span.into(); + spans.push_span_label(cause.span, unsatisfied_msg); spans } else { ident.span.into() }; - spans.push_span_label(ident.span, "in this trait".to_string()); + spans.push_span_label(ident.span, "in this trait"); let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); } // Unmet obligation coming from an `impl`. Some(Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), + kind: + hir::ItemKind::Impl(hir::Impl { + of_trait, self_ty, generics, .. + }), span: item_span, .. })) if !matches!( @@ -722,14 +727,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ExpnKind::Macro(MacroKind::Derive, _)) ) => { + let sized_pred = + unsatisfied_predicates.iter().any(|(pred, _, _)| { + match pred.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => { + Some(pred.def_id()) + == self.tcx.lang_items().sized_trait() + && pred.polarity == ty::ImplPolarity::Positive + } + _ => false, + } + }); + for param in generics.params { + if param.span == cause.span && sized_pred { + let (sp, sugg) = match param.colon_span { + Some(sp) => (sp.shrink_to_hi(), " ?Sized +"), + None => (param.span.shrink_to_hi(), ": ?Sized"), + }; + err.span_suggestion_verbose( + sp, + "consider relaxing the type parameter's implicit \ + `Sized` bound", + sugg, + Applicability::MachineApplicable, + ); + } + } if let Some(pred) = parent_p { // Done to add the "doesn't satisfy" `span_label`. let _ = format_pred(*pred); } skip_list.insert(p); - let mut spans = if cause_span != *item_span { - let mut spans: MultiSpan = cause_span.into(); - spans.push_span_label(cause_span, unsatisfied_msg); + let mut spans = if cause.span != *item_span { + let mut spans: MultiSpan = cause.span.into(); + spans.push_span_label(cause.span, unsatisfied_msg); spans } else { let mut spans = Vec::with_capacity(2); @@ -740,9 +771,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { spans.into() }; if let Some(trait_ref) = of_trait { - spans.push_span_label(trait_ref.path.span, String::new()); + spans.push_span_label(trait_ref.path.span, ""); } - spans.push_span_label(self_ty.span, String::new()); + spans.push_span_label(self_ty.span, ""); let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); @@ -987,6 +1018,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_ty, item_name, + args.map(|args| args.len()), source, out_of_scope_traits, &unsatisfied_predicates, @@ -1461,21 +1493,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }) .collect::<FxHashSet<_>>(); - let sm = self.tcx.sess.source_map(); let mut spans: MultiSpan = def_ids .iter() .filter_map(|def_id| { let span = self.tcx.def_span(*def_id); - if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) } + if span.is_dummy() { None } else { Some(span) } }) .collect::<Vec<_>>() .into(); for pred in &preds { match pred.self_ty().kind() { - ty::Adt(def, _) => { + ty::Adt(def, _) if def.did().is_local() => { spans.push_span_label( - sm.guess_head_span(self.tcx.def_span(def.did())), + self.tcx.def_span(def.did()), format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), ); } @@ -1518,7 +1549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Option<ObligationCause<'tcx>>, )], ) { - let mut derives = Vec::<(String, Span, String)>::new(); + let mut derives = Vec::<(String, Span, Symbol)>::new(); let mut traits = Vec::<Span>::new(); for (pred, _, _) in unsatisfied_predicates { let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() else { continue }; @@ -1551,12 +1582,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { derives.push(( self_name.clone(), self_span, - parent_diagnostic_name.to_string(), + parent_diagnostic_name, )); } } } - derives.push((self_name, self_span, diagnostic_name.to_string())); + derives.push((self_name, self_span, diagnostic_name)); } else { traits.push(self.tcx.def_span(trait_pred.def_id())); } @@ -1579,7 +1610,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } } - derives_grouped.push((self_name, self_span, trait_name)); + derives_grouped.push((self_name, self_span, trait_name.to_string())); } let len = traits.len(); @@ -1725,6 +1756,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, + inputs_len: Option<usize>, source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec<DefId>, unsatisfied_predicates: &[( @@ -1801,7 +1833,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not // implement the `AsRef` trait. let skip = skippable.contains(&did) - || (("Pin::new" == *pre) && (sym::as_ref == item_name.name)); + || (("Pin::new" == *pre) && (sym::as_ref == item_name.name)) + || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().inputs().len() != inputs_len); // Make sure the method is defined for the *actual* receiver: we don't // want to treat `Box<Self>` as a receiver if it only works because of // an autoderef to `&self` @@ -1951,9 +1984,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; // Obtain the span for `param` and use it for a structured suggestion. - if let (Some(param), Some(table)) = (param_type, self.in_progress_typeck_results) { - let table_owner = table.borrow().hir_owner; - let generics = self.tcx.generics_of(table_owner.to_def_id()); + if let Some(param) = param_type { + let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); let type_param = generics.type_param(param, self.tcx); let hir = self.tcx.hir(); if let Some(def_id) = type_param.def_id.as_local() { @@ -2081,9 +2113,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &potential_candidates[..] { [] => {} [trait_info] if trait_info.def_id.is_local() => { - let span = self.tcx.hir().span_if_local(trait_info.def_id).unwrap(); err.span_note( - self.tcx.sess.source_map().guess_head_span(span), + self.tcx.def_span(trait_info.def_id), &format!( "`{}` defines an item `{}`, perhaps you need to {} it", self.tcx.def_path_str(trait_info.def_id), diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index e26f211c1c189..849e96445d3ea 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -25,7 +25,7 @@ can be broken down into several distinct phases: - regionck: after main is complete, the regionck pass goes over all types looking for regions and making sure that they did not escape - into places they are not in scope. This may also influence the + into places where they are not in scope. This may also influence the final assignments of the various region variables if there is some flexibility. @@ -93,11 +93,7 @@ mod upvar; mod wfcheck; pub mod writeback; -use check::{ - check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types, - check_trait_item_well_formed, -}; -pub use check::{check_item_type, check_wf_new}; +use check::{check_abi, check_fn, check_mod_item_types}; pub use diverges::Diverges; pub use expectation::Expectation; pub use fn_ctxt::*; @@ -245,6 +241,7 @@ impl<'tcx> EnclosingBreakables<'tcx> { pub fn provide(providers: &mut Providers) { method::provide(providers); + wfcheck::provide(providers); *providers = Providers { typeck_item_bodies, typeck_const_arg, @@ -253,9 +250,6 @@ pub fn provide(providers: &mut Providers) { has_typeck_results, adt_destructor, used_trait_imports, - check_item_well_formed, - check_trait_item_well_formed, - check_impl_item_well_formed, check_mod_item_types, region_scope_tree, ..*providers @@ -374,7 +368,7 @@ fn typeck_with_fallback<'tcx>( let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { let param_env = tcx.param_env(def_id); - let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig { + let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig { let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None) @@ -384,13 +378,7 @@ fn typeck_with_fallback<'tcx>( check_abi(tcx, id, span, fn_sig.abi()); - // When normalizing the function signature, we assume all types are - // well-formed. So, we don't need to worry about the obligations - // from normalization. We could just discard these, but to align with - // compare_method and elsewhere, we just add implied bounds for - // these types. - let mut wf_tys = FxHashSet::default(); - // Compute the fty from point of view of inside the fn. + // Compute the function signature from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = inh.normalize_associated_types_in( body.value.span, @@ -398,10 +386,7 @@ fn typeck_with_fallback<'tcx>( param_env, fn_sig, ); - wf_tys.extend(fn_sig.inputs_and_output.iter()); - - let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0; - (fcx, wf_tys) + check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0 } else { let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); let expected_type = body_ty @@ -464,7 +449,7 @@ fn typeck_with_fallback<'tcx>( fcx.write_ty(id, expected_type); - (fcx, FxHashSet::default()) + fcx }; let fallback_has_occurred = fcx.type_inference_fallback(); @@ -496,11 +481,7 @@ fn typeck_with_fallback<'tcx>( fcx.check_asms(); - if fn_sig.is_some() { - fcx.regionck_fn(id, body, span, wf_tys); - } else { - fcx.regionck_expr(body); - } + fcx.infcx.skip_region_resolution(); fcx.resolve_type_vars_in_body(body) }); @@ -553,7 +534,7 @@ fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { } } -fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) { +fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { // Only restricted on wasm target for now if !tcx.sess.target.is_like_wasm { return; @@ -579,7 +560,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.sess.span_err(span, msg); + tcx.sess.span_err(tcx.def_span(id), msg); } } @@ -640,9 +621,8 @@ fn missing_items_err( // adding the associated item at the end of its body. let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); // Obtain the level of indentation ending in `sugg_sp`. - let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0); - // Make the whitespace that will make the suggestion have the right indentation. - let padding: String = " ".repeat(indentation); + let padding = + tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); for trait_item in missing_items { let snippet = suggestion_signature(trait_item, tcx); diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index c2f97a5051c96..d4bb3d43effe4 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -2,15 +2,17 @@ use super::method::MethodCallee; use super::{has_expected_num_generic_args, FnCtxt}; +use crate::check::Expectation; use rustc_ast as ast; use rustc_errors::{self, struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor, + self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; @@ -30,9 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op: hir::BinOp, lhs: &'tcx hir::Expr<'tcx>, rhs: &'tcx hir::Expr<'tcx>, + expected: Expectation<'tcx>, ) -> Ty<'tcx> { let (lhs_ty, rhs_ty, return_ty) = - self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes); + self.check_overloaded_binop(expr, lhs, rhs, op, IsAssign::Yes, expected); let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { @@ -50,6 +53,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(rhs_ty), Some(rhs), Op::Binary(op, IsAssign::Yes), + expected, ) .is_ok() { @@ -70,6 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op: hir::BinOp, lhs_expr: &'tcx hir::Expr<'tcx>, rhs_expr: &'tcx hir::Expr<'tcx>, + expected: Expectation<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -94,8 +99,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Otherwise, we always treat operators as if they are // overloaded. This is the way to be most flexible w/r/t // types that get inferred. - let (lhs_ty, rhs_ty, return_ty) = - self.check_overloaded_binop(expr, lhs_expr, rhs_expr, op, IsAssign::No); + let (lhs_ty, rhs_ty, return_ty) = self.check_overloaded_binop( + expr, + lhs_expr, + rhs_expr, + op, + IsAssign::No, + expected, + ); // Supply type inference hints if relevant. Probably these // hints should be enforced during select as part of the @@ -176,6 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_expr: &'tcx hir::Expr<'tcx>, op: hir::BinOp, is_assign: IsAssign, + expected: Expectation<'tcx>, ) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) { debug!( "check_overloaded_binop(expr.hir_id={}, op={:?}, is_assign={:?})", @@ -222,6 +234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(rhs_ty_var), Some(rhs_expr), Op::Binary(op, is_assign), + expected, ); // see `NB` above @@ -282,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { let source_map = self.tcx.sess.source_map(); - let (mut err, missing_trait, _use_output) = match is_assign { + let (mut err, missing_trait, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( self.tcx.sess, @@ -406,6 +419,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_expr, op, is_assign, + expected, ); self.add_type_neq_err_label( &mut err, @@ -415,6 +429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr, op, is_assign, + expected, ); } self.note_unmet_impls_on_type(&mut err, errors); @@ -429,6 +444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(rhs_ty), Some(rhs_expr), Op::Binary(op, is_assign), + expected, ) .is_ok() { @@ -490,19 +506,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(rhs_ty), Some(rhs_expr), Op::Binary(op, is_assign), + expected, ) .unwrap_err(); - let predicates = errors - .into_iter() - .filter_map(|error| error.obligation.predicate.to_opt_poly_trait_pred()) - .collect::<Vec<_>>(); - if !predicates.is_empty() { - for pred in predicates { - self.infcx.suggest_restricting_param_bound( - &mut err, - pred, - self.body_id, - ); + if !errors.is_empty() { + for error in errors { + if let Some(trait_pred) = + error.obligation.predicate.to_opt_poly_trait_pred() + { + let proj_pred = match error.obligation.cause.code() { + ObligationCauseCode::BinOp { + output_pred: Some(output_pred), + .. + } if use_output => { + output_pred.to_opt_poly_projection_pred() + } + _ => None, + }; + + self.infcx.suggest_restricting_param_bound( + &mut err, + trait_pred, + proj_pred, + self.body_id, + ); + } } } else if *ty != lhs_ty { // When we know that a missing bound is responsible, we don't show @@ -532,6 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { other_expr: &'tcx hir::Expr<'tcx>, op: hir::BinOp, is_assign: IsAssign, + expected: Expectation<'tcx>, ) -> bool /* did we suggest to call a function because of missing parentheses? */ { err.span_label(span, ty.to_string()); if let FnDef(def_id, _) = *ty.kind() { @@ -561,13 +590,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(other_ty), Some(other_expr), Op::Binary(op, is_assign), + expected, ) .is_ok() { let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { - ("( /* arguments */ )".to_string(), Applicability::HasPlaceholders) + ("( /* arguments */ )", Applicability::HasPlaceholders) } else { - ("()".to_string(), Applicability::MaybeIncorrect) + ("()", Applicability::MaybeIncorrect) }; err.span_suggestion_verbose( @@ -677,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ex: &'tcx hir::Expr<'tcx>, operand_ty: Ty<'tcx>, op: hir::UnOp, + expected: Expectation<'tcx>, ) -> Ty<'tcx> { assert!(op.is_by_value()); - match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span)) { + match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) { Ok(method) => { self.write_method_call(ex.hir_id, method); method.sig.output() @@ -712,6 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.infcx.suggest_restricting_param_bound( &mut err, pred, + None, self.body_id, ); } @@ -772,6 +804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { other_ty: Option<Ty<'tcx>>, other_ty_expr: Option<&'tcx hir::Expr<'tcx>>, op: Op, + expected: Expectation<'tcx>, ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> { let lang = self.tcx.lang_items(); @@ -856,7 +889,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opname = Ident::with_dummy_span(opname); let method = trait_did.and_then(|trait_did| { - self.lookup_op_method_in_trait(span, opname, trait_did, lhs_ty, other_ty, other_ty_expr) + self.lookup_op_method_in_trait( + span, + opname, + trait_did, + lhs_ty, + other_ty, + other_ty_expr, + expected, + ) }); match (method, trait_did) { @@ -867,8 +908,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } (None, None) => Err(vec![]), (None, Some(trait_did)) => { - let (obligation, _) = - self.obligation_for_op_method(span, trait_did, lhs_ty, other_ty, other_ty_expr); + let (obligation, _) = self.obligation_for_op_method( + span, + trait_did, + lhs_ty, + other_ty, + other_ty_expr, + expected, + ); let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx); fulfill.register_predicate_obligation(self, obligation); Err(fulfill.select_where_possible(&self.infcx)) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index f45b94bcdff45..fbfbfba5c2ad2 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -13,7 +13,7 @@ use rustc_hir::{HirId, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitable}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; @@ -663,6 +663,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::Mutability::Not => "", }; + let mut_var_suggestion = 'block: { + if !matches!(mutbl, ast::Mutability::Mut) { + break 'block None; + } + + let ident_kind = match binding_parent { + hir::Node::Param(_) => "parameter", + hir::Node::Local(_) => "variable", + hir::Node::Arm(_) => "binding", + + // Provide diagnostics only if the parent pattern is struct-like, + // i.e. where `mut binding` makes sense + hir::Node::Pat(Pat { kind, .. }) => match kind { + PatKind::Struct(..) + | PatKind::TupleStruct(..) + | PatKind::Or(..) + | PatKind::Tuple(..) + | PatKind::Slice(..) => "binding", + + PatKind::Wild + | PatKind::Binding(..) + | PatKind::Path(..) + | PatKind::Box(..) + | PatKind::Ref(..) + | PatKind::Lit(..) + | PatKind::Range(..) => break 'block None, + }, + + // Don't provide suggestions in other cases + _ => break 'block None, + }; + + Some(( + pat.span, + format!("to declare a mutable {ident_kind} use"), + format!("mut {binding}"), + )) + + }; + match binding_parent { // Check that there is explicit type (ie this is not a closure param with inferred type) // so we don't suggest moving something to the type that does not exist @@ -675,6 +715,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ], Applicability::MachineApplicable ); + + if let Some((sp, msg, sugg)) = mut_var_suggestion { + err.span_note(sp, format!("{msg}: `{sugg}`")); + } } hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => { // rely on match ergonomics or it might be nested `&&pat` @@ -684,6 +728,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "", Applicability::MaybeIncorrect, ); + + if let Some((sp, msg, sugg)) = mut_var_suggestion { + err.span_note(sp, format!("{msg}: `{sugg}`")); + } + } + _ if let Some((sp, msg, sugg)) = mut_var_suggestion => { + err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable); } _ => {} // don't provide suggestions in other cases #55175 } diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 9f1368a3e0777..0c33a243e108b 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -335,7 +335,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h match expr.kind { // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure { body, .. } + hir::ExprKind::Closure(&hir::Closure { body, .. }) | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); @@ -460,6 +460,7 @@ fn resolve_local<'tcx>( visitor: &mut RegionResolutionVisitor<'tcx>, pat: Option<&'tcx hir::Pat<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>, + els: Option<&'tcx hir::Block<'tcx>>, ) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); @@ -537,13 +538,18 @@ fn resolve_local<'tcx>( } } - // Make sure we visit the initializer first, so expr_and_pat_count remains correct + // Make sure we visit the initializer first, so expr_and_pat_count remains correct. + // The correct order, as shared between generator_interior, drop_ranges and intravisitor, + // is to walk initializer, followed by pattern bindings, finally followed by the `else` block. if let Some(expr) = init { visitor.visit_expr(expr); } if let Some(pat) = pat { visitor.visit_pat(pat); } + if let Some(els) = els { + visitor.visit_block(els); + } /// Returns `true` if `pat` match the `P&` non-terminal. /// @@ -764,7 +770,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // (i.e., `'static`), which means that after `g` returns, it drops, // and all the associated destruction scope rules apply. self.cx.var_parent = None; - resolve_local(self, None, Some(&body.value)); + resolve_local(self, None, Some(&body.value), None); } if body.generator_kind.is_some() { @@ -791,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { resolve_expr(self, ex); } fn visit_local(&mut self, l: &'tcx Local<'tcx>) { - resolve_local(self, Some(&l.pat), l.init); + resolve_local(self, Some(&l.pat), l.init, l.els) } } diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 161ec31793dd8..1c3c5f999bca8 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -1,106 +1,9 @@ -//! The region check is a final pass that runs over the AST after we have -//! inferred the type constraints but before we have actually finalized -//! the types. Its purpose is to embed a variety of region constraints. -//! Inserting these constraints as a separate pass is good because (1) it -//! localizes the code that has to do with region inference and (2) often -//! we cannot know what constraints are needed until the basic types have -//! been inferred. -//! -//! ### Interaction with the borrow checker -//! -//! In general, the job of the borrowck module (which runs later) is to -//! check that all soundness criteria are met, given a particular set of -//! regions. The job of *this* module is to anticipate the needs of the -//! borrow checker and infer regions that will satisfy its requirements. -//! It is generally true that the inference doesn't need to be sound, -//! meaning that if there is a bug and we inferred bad regions, the borrow -//! checker should catch it. This is not entirely true though; for -//! example, the borrow checker doesn't check subtyping, and it doesn't -//! check that region pointers are always live when they are used. It -//! might be worthwhile to fix this so that borrowck serves as a kind of -//! verification step -- that would add confidence in the overall -//! correctness of the compiler, at the cost of duplicating some type -//! checks and effort. -//! -//! ### Inferring the duration of borrows, automatic and otherwise -//! -//! Whenever we introduce a borrowed pointer, for example as the result of -//! a borrow expression `let x = &data`, the lifetime of the pointer `x` -//! is always specified as a region inference variable. `regionck` has the -//! job of adding constraints such that this inference variable is as -//! narrow as possible while still accommodating all uses (that is, every -//! dereference of the resulting pointer must be within the lifetime). -//! -//! #### Reborrows -//! -//! Generally speaking, `regionck` does NOT try to ensure that the data -//! `data` will outlive the pointer `x`. That is the job of borrowck. The -//! one exception is when "re-borrowing" the contents of another borrowed -//! pointer. For example, imagine you have a borrowed pointer `b` with -//! lifetime `L1` and you have an expression `&*b`. The result of this -//! expression will be another borrowed pointer with lifetime `L2` (which is -//! an inference variable). The borrow checker is going to enforce the -//! constraint that `L2 < L1`, because otherwise you are re-borrowing data -//! for a lifetime larger than the original loan. However, without the -//! routines in this module, the region inferencer would not know of this -//! dependency and thus it might infer the lifetime of `L2` to be greater -//! than `L1` (issue #3148). -//! -//! There are a number of troublesome scenarios in the tests -//! `region-dependent-*.rs`, but here is one example: -//! -//! struct Foo { i: i32 } -//! struct Bar { foo: Foo } -//! fn get_i<'a>(x: &'a Bar) -> &'a i32 { -//! let foo = &x.foo; // Lifetime L1 -//! &foo.i // Lifetime L2 -//! } -//! -//! Note that this comes up either with `&` expressions, `ref` -//! bindings, and `autorefs`, which are the three ways to introduce -//! a borrow. -//! -//! The key point here is that when you are borrowing a value that -//! is "guaranteed" by a borrowed pointer, you must link the -//! lifetime of that borrowed pointer (`L1`, here) to the lifetime of -//! the borrow itself (`L2`). What do I mean by "guaranteed" by a -//! borrowed pointer? I mean any data that is reached by first -//! dereferencing a borrowed pointer and then either traversing -//! interior offsets or boxes. We say that the guarantor -//! of such data is the region of the borrowed pointer that was -//! traversed. This is essentially the same as the ownership -//! relation, except that a borrowed pointer never owns its -//! contents. - -use crate::check::dropck; -use crate::check::FnCtxt; -use crate::mem_categorization as mc; use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::stable_set::FxHashSet; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::PatKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{self, InferCtxt, RegionObligation}; -use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; -use rustc_middle::ty::adjustment; -use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; -use std::ops::Deref; - -// a variation on try that just returns unit -macro_rules! ignore_err { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(_) => { - debug!("ignoring mem-categorization error!"); - return (); - } - } - }; -} +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::Ty; pub(crate) trait OutlivesEnvironmentExt<'tcx> { fn add_implied_bounds( @@ -108,7 +11,6 @@ pub(crate) trait OutlivesEnvironmentExt<'tcx> { infcx: &InferCtxt<'_, 'tcx>, fn_sig_tys: FxHashSet<Ty<'tcx>>, body_id: hir::HirId, - span: Span, ); } @@ -135,751 +37,11 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { infcx: &InferCtxt<'a, 'tcx>, fn_sig_tys: FxHashSet<Ty<'tcx>>, body_id: hir::HirId, - span: Span, ) { for ty in fn_sig_tys { let ty = infcx.resolve_vars_if_possible(ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); + let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty); self.add_outlives_bounds(Some(infcx), implied_bounds) } } } - -/////////////////////////////////////////////////////////////////////////// -// PUBLIC ENTRY POINTS - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) { - let subject = self.tcx.hir().body_owner_def_id(body.id()); - let id = body.value.hir_id; - let mut rcx = RegionCtxt::new(self, id, Subject(subject), self.param_env); - - // There are no add'l implied bounds when checking a - // standalone expr (e.g., the `E` in a type like `[u32; E]`). - rcx.outlives_environment.save_implied_bounds(id); - - if !self.errors_reported_since_creation() { - // regionck assumes typeck succeeded - rcx.visit_body(body); - rcx.visit_region_obligations(id); - } - // Checked by NLL - rcx.fcx.skip_region_resolution(); - } - - /// Region checking during the WF phase for items. `wf_tys` are the - /// types from which we should derive implied bounds, if any. - #[instrument(level = "debug", skip(self))] - pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet<Ty<'tcx>>) { - let subject = self.tcx.hir().local_def_id(item_id); - let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env); - rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span); - rcx.outlives_environment.save_implied_bounds(item_id); - rcx.visit_region_obligations(item_id); - rcx.resolve_regions_and_report_errors(); - } - - /// Region check a function body. Not invoked on closures, but - /// only on the "root" fn item (in which closures may be - /// embedded). Walks the function body and adds various add'l - /// constraints that are needed for region inference. This is - /// separated both to isolate "pure" region constraints from the - /// rest of type check and because sometimes we need type - /// inference to have completed before we can determine which - /// constraints to add. - pub(crate) fn regionck_fn( - &self, - fn_id: hir::HirId, - body: &'tcx hir::Body<'tcx>, - span: Span, - wf_tys: FxHashSet<Ty<'tcx>>, - ) { - debug!("regionck_fn(id={})", fn_id); - let subject = self.tcx.hir().body_owner_def_id(body.id()); - let hir_id = body.value.hir_id; - let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env); - // We need to add the implied bounds from the function signature - rcx.outlives_environment.add_implied_bounds(self, wf_tys, fn_id, span); - rcx.outlives_environment.save_implied_bounds(fn_id); - - if !self.errors_reported_since_creation() { - // regionck assumes typeck succeeded - rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id)); - } - - // Checked by NLL - rcx.fcx.skip_region_resolution(); - } -} - -/////////////////////////////////////////////////////////////////////////// -// INTERNALS - -pub struct RegionCtxt<'a, 'tcx> { - pub fcx: &'a FnCtxt<'a, 'tcx>, - - outlives_environment: OutlivesEnvironment<'tcx>, - - // id of innermost fn body id - body_id: hir::HirId, - body_owner: LocalDefId, - - // id of AST node being analyzed (the subject of the analysis). - subject_def_id: LocalDefId, -} - -impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> { - type Target = FnCtxt<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - self.fcx - } -} - -pub struct Subject(LocalDefId); - -impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { - pub fn new( - fcx: &'a FnCtxt<'a, 'tcx>, - initial_body_id: hir::HirId, - Subject(subject): Subject, - param_env: ty::ParamEnv<'tcx>, - ) -> RegionCtxt<'a, 'tcx> { - let outlives_environment = OutlivesEnvironment::new(param_env); - RegionCtxt { - fcx, - body_id: initial_body_id, - body_owner: subject, - subject_def_id: subject, - outlives_environment, - } - } - - /// Try to resolve the type for the given node, returning `t_err` if an error results. Note that - /// we never care about the details of the error, the same error will be detected and reported - /// in the writeback phase. - /// - /// Note one important point: we do not attempt to resolve *region variables* here. This is - /// because regionck is essentially adding constraints to those region variables and so may yet - /// influence how they are resolved. - /// - /// Consider this silly example: - /// - /// ```ignore UNSOLVED (does replacing @i32 with Box<i32> preserve the desired semantics for the example?) - /// fn borrow(x: &i32) -> &i32 {x} - /// fn foo(x: @i32) -> i32 { // block: B - /// let b = borrow(x); // region: <R0> - /// *b - /// } - /// ``` - /// - /// Here, the region of `b` will be `<R0>`. `<R0>` is constrained to be some subregion of the - /// block B and some superregion of the call. If we forced it now, we'd choose the smaller - /// region (the call). But that would make the *b illegal. Since we don't resolve, the type - /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and - /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B. - pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_vars_if_possible(unresolved_ty) - } - - /// Try to resolve the type for the given node. - fn resolve_node_type(&self, id: hir::HirId) -> Ty<'tcx> { - let t = self.node_ty(id); - self.resolve_type(t) - } - - /// This is the "main" function when region-checking a function item or a - /// closure within a function item. It begins by updating various fields - /// (e.g., `outlives_environment`) to be appropriate to the function and - /// then adds constraints derived from the function body. - /// - /// Note that it does **not** restore the state of the fields that - /// it updates! This is intentional, since -- for the main - /// function -- we wish to be able to read the final - /// `outlives_environment` and other fields from the caller. For - /// closures, however, we save and restore any "scoped state" - /// before we invoke this function. (See `visit_fn` in the - /// `intravisit::Visitor` impl below.) - fn visit_fn_body( - &mut self, - id: hir::HirId, // the id of the fn itself - body: &'tcx hir::Body<'tcx>, - span: Span, - ) { - // When we enter a function, we can derive - debug!("visit_fn_body(id={:?})", id); - - let body_id = body.id(); - self.body_id = body_id.hir_id; - self.body_owner = self.tcx.hir().body_owner_def_id(body_id); - - let Some(fn_sig) = self.typeck_results.borrow().liberated_fn_sigs().get(id) else { - bug!("No fn-sig entry for id={:?}", id); - }; - - // Collect the types from which we create inferred bounds. - // For the return type, if diverging, substitute `bool` just - // because it will have no effect. - // - // FIXME(#27579) return types should not be implied bounds - let fn_sig_tys: FxHashSet<_> = - fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect(); - - self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span); - self.outlives_environment.save_implied_bounds(body_id.hir_id); - self.link_fn_params(body.params); - self.visit_body(body); - self.visit_region_obligations(body_id.hir_id); - } - - fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) { - debug!("visit_inline_const(id={:?})", id); - - // Save state of current function. We will restore afterwards. - let old_body_id = self.body_id; - let old_body_owner = self.body_owner; - let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); - - let body_id = body.id(); - self.body_id = body_id.hir_id; - self.body_owner = self.tcx.hir().body_owner_def_id(body_id); - - self.outlives_environment.save_implied_bounds(body_id.hir_id); - - self.visit_body(body); - self.visit_region_obligations(body_id.hir_id); - - // Restore state from previous function. - self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); - self.body_id = old_body_id; - self.body_owner = old_body_owner; - } - - fn visit_region_obligations(&mut self, hir_id: hir::HirId) { - debug!("visit_region_obligations: hir_id={:?}", hir_id); - - // region checking can introduce new pending obligations - // which, when processed, might generate new region - // obligations. So make sure we process those. - self.select_all_obligations_or_error(); - } - - fn resolve_regions_and_report_errors(&self) { - self.infcx.process_registered_region_obligations( - self.outlives_environment.region_bound_pairs_map(), - Some(self.tcx.lifetimes.re_root_empty), - self.param_env, - ); - - self.fcx.resolve_regions_and_report_errors( - self.subject_def_id.to_def_id(), - &self.outlives_environment, - ); - } - - fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) { - debug!("regionck::visit_pat(pat={:?})", pat); - pat.each_binding(|_, hir_id, span, _| { - let typ = self.resolve_node_type(hir_id); - let body_id = self.body_id; - dropck::check_drop_obligations(self, typ, span, body_id); - }) - } -} - -impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { - // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local, - // However, right now we run into an issue whereby some free - // regions are not properly related if they appear within the - // types of arguments that must be inferred. This could be - // addressed by deferring the construction of the region - // hierarchy, and in particular the relationships between free - // regions, until regionck, as described in #3238. - - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl<'tcx>, - body_id: hir::BodyId, - span: Span, - hir_id: hir::HirId, - ) { - assert!( - matches!(fk, intravisit::FnKind::Closure), - "visit_fn invoked for something other than a closure" - ); - - // Save state of current function before invoking - // `visit_fn_body`. We will restore afterwards. - let old_body_id = self.body_id; - let old_body_owner = self.body_owner; - let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); - - let body = self.tcx.hir().body(body_id); - self.visit_fn_body(hir_id, body, span); - - // Restore state from previous function. - self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); - self.body_id = old_body_id; - self.body_owner = old_body_owner; - } - - //visit_pat: visit_pat, // (..) see above - - fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { - // see above - self.constrain_bindings_in_pat(arm.pat); - intravisit::walk_arm(self, arm); - } - - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { - // see above - self.constrain_bindings_in_pat(l.pat); - self.link_local(l); - intravisit::walk_local(self, l); - } - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - // Check any autoderefs or autorefs that appear. - let cmt_result = self.constrain_adjustments(expr); - - // If necessary, constrain destructors in this expression. This will be - // the adjusted form if there is an adjustment. - match cmt_result { - Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(&head_cmt, expr.span); - } - Err(..) => { - self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd"); - } - } - - match expr.kind { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => { - self.link_addr_of(expr, m, base); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Match(ref discr, arms, _) => { - self.link_match(discr, arms); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::ConstBlock(anon_const) => { - let body = self.tcx.hir().body(anon_const.body); - self.visit_inline_const(anon_const.hir_id, body); - } - - _ => intravisit::walk_expr(self, expr), - } - } -} - -impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { - /// Creates a temporary `MemCategorizationContext` and pass it to the closure. - fn with_mc<F, R>(&self, f: F) -> R - where - F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'tcx>) -> R, - { - f(mc::MemCategorizationContext::new( - &self.infcx, - self.outlives_environment.param_env, - self.body_owner, - &self.typeck_results.borrow(), - )) - } - - /// Invoked on any adjustments that occur. Checks that if this is a region pointer being - /// dereferenced, the lifetime of the pointer includes the deref expr. - fn constrain_adjustments( - &mut self, - expr: &hir::Expr<'_>, - ) -> mc::McResult<PlaceWithHirId<'tcx>> { - debug!("constrain_adjustments(expr={:?})", expr); - - let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; - - let typeck_results = self.typeck_results.borrow(); - let adjustments = typeck_results.expr_adjustments(expr); - if adjustments.is_empty() { - return Ok(place); - } - - debug!("constrain_adjustments: adjustments={:?}", adjustments); - - // If necessary, constrain destructors in the unadjusted form of this - // expression. - self.check_safety_of_rvalue_destructor_if_necessary(&place, expr.span); - - for adjustment in adjustments { - debug!("constrain_adjustments: adjustment={:?}, place={:?}", adjustment, place); - - if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind { - self.link_region( - expr.span, - deref.region, - ty::BorrowKind::from_mutbl(deref.mutbl), - &place, - ); - } - - if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { - self.link_autoref(expr, &place, autoref); - } - - place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?; - } - - Ok(place) - } - - fn check_safety_of_rvalue_destructor_if_necessary( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - span: Span, - ) { - if let PlaceBase::Rvalue = place_with_id.place.base { - if place_with_id.place.projections.is_empty() { - let typ = self.resolve_type(place_with_id.place.ty()); - let body_id = self.body_id; - dropck::check_drop_obligations(self, typ, span, body_id); - } - } - } - /// Adds constraints to inference such that `T: 'a` holds (or - /// reports an error if it cannot). - /// - /// # Parameters - /// - /// - `origin`, the reason we need this constraint - /// - `ty`, the type `T` - /// - `region`, the region `'a` - pub fn type_must_outlive( - &self, - origin: infer::SubregionOrigin<'tcx>, - ty: Ty<'tcx>, - region: ty::Region<'tcx>, - ) { - self.infcx.register_region_obligation( - self.body_id, - RegionObligation { sub_region: region, sup_type: ty, origin }, - ); - } - - /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the - /// resulting pointer is linked to the lifetime of its guarantor (if any). - fn link_addr_of( - &mut self, - expr: &hir::Expr<'_>, - mutability: hir::Mutability, - base: &hir::Expr<'_>, - ) { - debug!("link_addr_of(expr={:?}, base={:?})", expr, base); - - let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base))); - - debug!("link_addr_of: cmt={:?}", cmt); - - self.link_region_from_node_type(expr.span, expr.hir_id, mutability, &cmt); - } - - /// Computes the guarantors for any ref bindings in a `let` and - /// then ensures that the lifetime of the resulting pointer is - /// linked to the lifetime of the initialization expression. - fn link_local(&self, local: &hir::Local<'_>) { - debug!("regionck::for_local()"); - let init_expr = match local.init { - None => { - return; - } - Some(expr) => &*expr, - }; - let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); - self.link_pattern(discr_cmt, local.pat); - } - - /// Computes the guarantors for any ref bindings in a match and - /// then ensures that the lifetime of the resulting pointer is - /// linked to the lifetime of its guarantor (if any). - fn link_match(&self, discr: &hir::Expr<'_>, arms: &[hir::Arm<'_>]) { - debug!("regionck::for_match()"); - let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); - debug!("discr_cmt={:?}", discr_cmt); - for arm in arms { - self.link_pattern(discr_cmt.clone(), arm.pat); - } - } - - /// Computes the guarantors for any ref bindings in a match and - /// then ensures that the lifetime of the resulting pointer is - /// linked to the lifetime of its guarantor (if any). - fn link_fn_params(&self, params: &[hir::Param<'_>]) { - for param in params { - let param_ty = self.node_ty(param.hir_id); - let param_cmt = - self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty)); - debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param); - self.link_pattern(param_cmt, param.pat); - } - } - - /// Link lifetimes of any ref bindings in `root_pat` to the pointers found - /// in the discriminant, if needed. - fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) { - debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); - ignore_err!(self.with_mc(|mc| { - mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| { - // `ref x` pattern - if let PatKind::Binding(..) = kind - && let Some(ty::BindByReference(mutbl)) = mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span) { - self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt); - } - }) - })); - } - - /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being - /// autoref'd. - fn link_autoref( - &self, - expr: &hir::Expr<'_>, - expr_cmt: &PlaceWithHirId<'tcx>, - autoref: &adjustment::AutoBorrow<'tcx>, - ) { - debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); - - match *autoref { - adjustment::AutoBorrow::Ref(r, m) => { - self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt); - } - - adjustment::AutoBorrow::RawPtr(_) => {} - } - } - - /// Like `link_region()`, except that the region is extracted from the type of `id`, - /// which must be some reference (`&T`, `&str`, etc). - fn link_region_from_node_type( - &self, - span: Span, - id: hir::HirId, - mutbl: hir::Mutability, - cmt_borrowed: &PlaceWithHirId<'tcx>, - ) { - debug!( - "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", - id, mutbl, cmt_borrowed - ); - - let rptr_ty = self.resolve_node_type(id); - if let ty::Ref(r, _, _) = rptr_ty.kind() { - debug!("rptr_ty={}", rptr_ty); - self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); - } - } - - /// Informs the inference engine that `borrow_cmt` is being borrowed with - /// kind `borrow_kind` and lifetime `borrow_region`. - /// In order to ensure borrowck is satisfied, this may create constraints - /// between regions, as explained in `link_reborrowed_region()`. - fn link_region( - &self, - span: Span, - borrow_region: ty::Region<'tcx>, - borrow_kind: ty::BorrowKind, - borrow_place: &PlaceWithHirId<'tcx>, - ) { - let origin = infer::DataBorrowed(borrow_place.place.ty(), span); - self.type_must_outlive(origin, borrow_place.place.ty(), borrow_region); - - for pointer_ty in borrow_place.place.deref_tys() { - debug!( - "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})", - borrow_region, borrow_kind, borrow_place - ); - match *pointer_ty.kind() { - ty::RawPtr(_) => return, - ty::Ref(ref_region, _, ref_mutability) => { - if self.link_reborrowed_region(span, borrow_region, ref_region, ref_mutability) - { - return; - } - } - _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty), - } - } - if let PlaceBase::Upvar(upvar_id) = borrow_place.place.base { - self.link_upvar_region(span, borrow_region, upvar_id); - } - } - - /// This is the most complicated case: the path being borrowed is - /// itself the referent of a borrowed pointer. Let me give an - /// example fragment of code to make clear(er) the situation: - /// - /// ```ignore (incomplete Rust code) - /// let r: &'a mut T = ...; // the original reference "r" has lifetime 'a - /// ... - /// &'z *r // the reborrow has lifetime 'z - /// ``` - /// - /// Now, in this case, our primary job is to add the inference - /// constraint that `'z <= 'a`. Given this setup, let's clarify the - /// parameters in (roughly) terms of the example: - /// - /// ```plain,ignore (pseudo-Rust) - /// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T` - /// borrow_region ^~ ref_region ^~ - /// borrow_kind ^~ ref_kind ^~ - /// ref_cmt ^ - /// ``` - /// - /// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc). - /// - /// There is a complication beyond the simple scenario I just painted: there - /// may in fact be more levels of reborrowing. In the example, I said the - /// borrow was like `&'z *r`, but it might in fact be a borrow like - /// `&'z **q` where `q` has type `&'a &'b mut T`. In that case, we want to - /// ensure that `'z <= 'a` and `'z <= 'b`. - /// - /// The return value of this function indicates whether we *don't* need to - /// the recurse to the next reference up. - /// - /// This is explained more below. - fn link_reborrowed_region( - &self, - span: Span, - borrow_region: ty::Region<'tcx>, - ref_region: ty::Region<'tcx>, - ref_mutability: hir::Mutability, - ) -> bool { - debug!("link_reborrowed_region: {:?} <= {:?}", borrow_region, ref_region); - self.sub_regions(infer::Reborrow(span), borrow_region, ref_region); - - // Decide whether we need to recurse and link any regions within - // the `ref_cmt`. This is concerned for the case where the value - // being reborrowed is in fact a borrowed pointer found within - // another borrowed pointer. For example: - // - // let p: &'b &'a mut T = ...; - // ... - // &'z **p - // - // What makes this case particularly tricky is that, if the data - // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires - // not only that `'z <= 'a`, (as before) but also `'z <= 'b` - // (otherwise the user might mutate through the `&mut T` reference - // after `'b` expires and invalidate the borrow we are looking at - // now). - // - // So let's re-examine our parameters in light of this more - // complicated (possible) scenario: - // - // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T` - // borrow_region ^~ ref_region ^~ - // borrow_kind ^~ ref_kind ^~ - // ref_cmt ^~~ - // - // (Note that since we have not examined `ref_cmt.cat`, we don't - // know whether this scenario has occurred; but I wanted to show - // how all the types get adjusted.) - match ref_mutability { - hir::Mutability::Not => { - // The reference being reborrowed is a shareable ref of - // type `&'a T`. In this case, it doesn't matter where we - // *found* the `&T` pointer, the memory it references will - // be valid and immutable for `'a`. So we can stop here. - true - } - - hir::Mutability::Mut => { - // The reference being reborrowed is either an `&mut T`. This is - // the case where recursion is needed. - false - } - } - } - - /// An upvar may be behind up to 2 references: - /// - /// * One can come from the reference to a "by-reference" upvar. - /// * Another one can come from the reference to the closure itself if it's - /// a `FnMut` or `Fn` closure. - /// - /// This function links the lifetimes of those references to the lifetime - /// of the borrow that's provided. See [RegionCtxt::link_reborrowed_region] for some - /// more explanation of this in the general case. - /// - /// We also supply a *cause*, and in this case we set the cause to - /// indicate that the reference being "reborrowed" is itself an upvar. This - /// provides a nicer error message should something go wrong. - fn link_upvar_region( - &self, - span: Span, - borrow_region: ty::Region<'tcx>, - upvar_id: ty::UpvarId, - ) { - debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id); - // A by-reference upvar can't be borrowed for longer than the - // upvar is borrowed from the environment. - let closure_local_def_id = upvar_id.closure_expr_id; - let mut all_captures_are_imm_borrow = true; - for captured_place in self - .typeck_results - .borrow() - .closure_min_captures - .get(&closure_local_def_id.to_def_id()) - .and_then(|root_var_min_cap| root_var_min_cap.get(&upvar_id.var_path.hir_id)) - .into_iter() - .flatten() - { - match captured_place.info.capture_kind { - ty::UpvarCapture::ByRef(upvar_borrow) => { - self.sub_regions( - infer::ReborrowUpvar(span, upvar_id), - borrow_region, - captured_place.region.unwrap(), - ); - if let ty::ImmBorrow = upvar_borrow { - debug!("link_upvar_region: capture by shared ref"); - } else { - all_captures_are_imm_borrow = false; - } - } - ty::UpvarCapture::ByValue => { - all_captures_are_imm_borrow = false; - } - } - } - if all_captures_are_imm_borrow { - return; - } - let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_local_def_id); - let ty = self.resolve_node_type(fn_hir_id); - debug!("link_upvar_region: ty={:?}", ty); - - // A closure capture can't be borrowed for longer than the - // reference to the closure. - if let ty::Closure(_, substs) = ty.kind() { - match self.infcx.closure_kind(substs) { - Some(ty::ClosureKind::Fn | ty::ClosureKind::FnMut) => { - // Region of environment pointer - let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: upvar_id.closure_expr_id.to_def_id(), - bound_region: ty::BrEnv, - })); - self.sub_regions( - infer::ReborrowUpvar(span, upvar_id), - borrow_region, - env_region, - ); - } - Some(ty::ClosureKind::FnOnce) => {} - None => { - span_bug!(span, "Have not inferred closure kind before regionck"); - } - } - } - } -} diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 0837d9c4a2024..3bd3e2d80917d 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -142,7 +142,7 @@ struct InferBorrowKindVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { match expr.kind { - hir::ExprKind::Closure { capture_clause, body: body_id, .. } => { + hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => { let body = self.fcx.tcx.hir().body(body_id); self.visit_body(body); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); @@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads); - if self.tcx.sess.opts.debugging_opts.profile_closures { + if self.tcx.sess.opts.unstable_opts.profile_closures { self.typeck_results.borrow_mut().closure_size_eval.insert( closure_def_id, ClosureSizeProfileData { @@ -747,14 +747,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (migration_string, migrated_variables_concat) = migration_suggestion_for_2229(self.tcx, &need_migrations); - let local_def_id = closure_def_id.expect_local(); - let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); - let closure_span = self.tcx.hir().span(closure_hir_id); - let closure_head_span = self.tcx.sess.source_map().guess_head_span(closure_span); + let closure_hir_id = + self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let closure_head_span = self.tcx.def_span(closure_def_id); self.tcx.struct_span_lint_hir( lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_hir_id, - closure_head_span, + closure_head_span, |lint| { let mut diagnostics_builder = lint.build( &reasons.migration_message(), @@ -827,12 +826,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { migrated_variables_concat ); + let closure_span = self.tcx.hir().span_with_body(closure_hir_id); let mut closure_body_span = { // If the body was entirely expanded from a macro // invocation, i.e. the body is not contained inside the // closure span, then we walk up the expansion until we // find the span before the expansion. - let s = self.tcx.hir().span(body_id.hir_id); + let s = self.tcx.hir().span_with_body(body_id.hir_id); s.find_ancestor_inside(closure_span).unwrap_or(s) }; @@ -1707,12 +1707,14 @@ fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> Span { hir::Node::Item(item) => match item.kind { hir::ItemKind::Fn(_, _, owner_id) => tcx.hir().span(owner_id.hir_id), _ => { - bug!("Drop location span error: need to handle more ItemKind {:?}", item.kind); + bug!("Drop location span error: need to handle more ItemKind '{:?}'", item.kind); } }, hir::Node::Block(block) => tcx.hir().span(block.hir_id), + hir::Node::TraitItem(item) => tcx.hir().span(item.hir_id()), + hir::Node::ImplItem(item) => tcx.hir().span(item.hir_id()), _ => { - bug!("Drop location span error: need to handle more Node {:?}", owner_node); + bug!("Drop location span error: need to handle more Node '{:?}'", owner_node); } }; tcx.sess.source_map().end_point(owner_span) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 7931215389575..6df59ea10969c 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,72 +1,130 @@ use crate::check::regionck::OutlivesEnvironmentExt; -use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; - use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit as hir_visit; -use rustc_hir::intravisit::Visitor; -use rustc_hir::itemlikevisit::ParItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_middle::hir::nested_filter; +use rustc_infer::traits::Normalized; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, TypeVisitor, + self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, + TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::autoderef::Autoderef; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::NoSolution; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, +}; use std::cell::LazyCell; use std::convert::TryInto; use std::iter; -use std::ops::ControlFlow; +use std::ops::{ControlFlow, Deref}; -/// Helper type of a temporary returned by `.for_item(...)`. -/// This is necessary because we can't write the following bound: -/// -/// ```ignore (illustrative) -/// F: for<'b, 'tcx> where 'tcx FnOnce(FnCtxt<'b, 'tcx>) -/// ``` -pub(super) struct CheckWfFcxBuilder<'tcx> { - inherited: super::InheritedBuilder<'tcx>, - id: hir::HirId, +pub(super) struct WfCheckingCtxt<'a, 'tcx> { + pub(super) ocx: ObligationCtxt<'a, 'tcx>, span: Span, + body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, } +impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> { + type Target = ObligationCtxt<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.ocx + } +} + +impl<'tcx> WfCheckingCtxt<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.ocx.infcx.tcx + } -impl<'tcx> CheckWfFcxBuilder<'tcx> { - pub(super) fn with_fcx<F>(&mut self, f: F) + fn normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T where - F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet<Ty<'tcx>>, + T: TypeFoldable<'tcx>, { - let id = self.id; - let span = self.span; - let param_env = self.param_env; - self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, param_env, id); - if !inh.tcx.features().trivial_bounds { - // As predicates are cached rather than obligations, this - // needs to be called first so that they are checked with an - // empty `param_env`. - check_false_global_bounds(&fcx, span, id); - } - let wf_tys = f(&fcx); - fcx.select_all_obligations_or_error(); - fcx.regionck_item(id, span, wf_tys); - }); + self.ocx.normalize( + ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)), + self.param_env, + value, + ) + } + + fn register_wf_obligation( + &self, + span: Span, + loc: Option<WellFormedLoc>, + arg: ty::GenericArg<'tcx>, + ) { + let cause = + traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)); + self.ocx.register_obligation(traits::Obligation::new( + cause, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()), + )); + } +} + +pub(super) fn enter_wf_checking_ctxt<'tcx, F>( + tcx: TyCtxt<'tcx>, + span: Span, + body_def_id: LocalDefId, + f: F, +) where + F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> FxHashSet<Ty<'tcx>>, +{ + let param_env = tcx.param_env(body_def_id); + let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id); + tcx.infer_ctxt().enter(|ref infcx| { + let ocx = ObligationCtxt::new(infcx); + let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env }; + + if !tcx.features().trivial_bounds { + wfcx.check_false_global_bounds() + } + let wf_tys = f(&mut wfcx); + let errors = wfcx.select_all_or_error(); + if !errors.is_empty() { + infcx.report_fulfillment_errors(&errors, None, false); + return; + } + + let mut outlives_environment = OutlivesEnvironment::new(param_env); + outlives_environment.add_implied_bounds(infcx, wf_tys, body_id); + infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); + }) +} + +fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let node = tcx.hir().expect_owner(def_id); + match node { + hir::OwnerNode::Crate(_) => {} + hir::OwnerNode::Item(item) => check_item(tcx, item), + hir::OwnerNode::TraitItem(item) => check_trait_item(tcx, item), + hir::OwnerNode::ImplItem(item) => check_impl_item(tcx, item), + hir::OwnerNode::ForeignItem(item) => check_foreign_item(tcx, item), + } + + if let Some(generics) = node.generics() { + for param in generics.params { + check_param_wf(tcx, param) + } } } @@ -84,8 +142,8 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> { /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. #[instrument(skip(tcx), level = "debug")] -pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let item = tcx.hir().expect_item(def_id); +fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { + let def_id = item.def_id; debug!( ?item.def_id, @@ -156,32 +214,18 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { hir::ItemKind::Const(ty, ..) => { check_item_type(tcx, item.def_id, ty.span, false); } - hir::ItemKind::ForeignMod { items, .. } => { - for it in items.iter() { - let it = tcx.hir().foreign_item(it.id); - match it.kind { - hir::ForeignItemKind::Fn(decl, ..) => { - check_item_fn(tcx, it.def_id, it.ident, it.span, decl) - } - hir::ForeignItemKind::Static(ty, ..) => { - check_item_type(tcx, it.def_id, ty.span, true) - } - hir::ForeignItemKind::Type => (), - } - } - } hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { - check_type_defn(tcx, item, false, |fcx| vec![fcx.non_enum_variant(struct_def)]); + check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]); check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemKind::Union(ref struct_def, ref ast_generics) => { - check_type_defn(tcx, item, true, |fcx| vec![fcx.non_enum_variant(struct_def)]); + check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]); check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemKind::Enum(ref enum_def, ref ast_generics) => { - check_type_defn(tcx, item, true, |fcx| fcx.enum_variants(enum_def)); + check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def)); check_variances_for_type_defn(tcx, item, ast_generics); } @@ -191,13 +235,31 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { hir::ItemKind::TraitAlias(..) => { check_trait(tcx, item); } + // `ForeignItem`s are handled separately. + hir::ItemKind::ForeignMod { .. } => {} _ => {} } } -pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let trait_item = tcx.hir().expect_trait_item(def_id); +fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { + let def_id = item.def_id; + + debug!( + ?item.def_id, + item.name = ? tcx.def_path_str(def_id.to_def_id()) + ); + + match item.kind { + hir::ForeignItemKind::Fn(decl, ..) => { + check_item_fn(tcx, item.def_id, item.ident, item.span, decl) + } + hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, item.def_id, ty.span, true), + hir::ForeignItemKind::Type => (), + } +} + +fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { + let def_id = trait_item.def_id; let (method_sig, span) = match trait_item.kind { hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span), @@ -207,7 +269,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_object_unsafe_self_trait_by_name(tcx, trait_item); check_associated_item(tcx, trait_item.def_id, span, method_sig); - let encl_trait_def_id = tcx.hir().get_parent_item(hir_id); + let encl_trait_def_id = tcx.local_parent(def_id); let encl_trait = tcx.hir().expect_item(encl_trait_def_id); let encl_trait_def_id = encl_trait.def_id.to_def_id(); let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() { @@ -596,13 +658,7 @@ fn ty_known_to_outlive<'tcx>( ) -> bool { resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| { let origin = infer::RelateParamBound(DUMMY_SP, ty, None); - let outlives = &mut TypeOutlives::new( - infcx, - tcx, - region_bound_pairs, - Some(infcx.tcx.lifetimes.re_root_empty), - param_env, - ); + let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env); outlives.type_must_outlive(origin, ty, region); }) } @@ -643,13 +699,12 @@ fn resolve_regions_with_wf_tys<'tcx>( // call individually. tcx.infer_ctxt().enter(|infcx| { let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); - outlives_environment.save_implied_bounds(id); - let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap(); + outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id); + let region_bound_pairs = outlives_environment.region_bound_pairs(); add_constraints(&infcx, region_bound_pairs); - let errors = infcx.resolve_regions(id.expect_owner().to_def_id(), &outlives_environment); + let errors = infcx.resolve_regions(&outlives_environment); debug!(?errors, "errors"); @@ -770,8 +825,8 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem } } -pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let impl_item = tcx.hir().expect_impl_item(def_id); +fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { + let def_id = impl_item.def_id; let (method_sig, span) = match impl_item.kind { hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span), @@ -780,7 +835,7 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.def_id, span, method_sig); + check_associated_item(tcx, def_id, span, method_sig); } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { @@ -810,50 +865,62 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } if let Some(non_structural_match_ty) = - traits::search_for_structural_match_violation(param.span, tcx, ty) + traits::search_for_structural_match_violation(param.span, tcx, ty, false) { // We use the same error code in both branches, because this is really the same // issue: we just special-case the message for type parameters to make it // clearer. - if let ty::Param(_) = ty.peel_refs().kind() { - // Const parameters may not have type parameters as their types, - // because we cannot be sure that the type parameter derives `PartialEq` - // and `Eq` (just implementing them is not enough for `structural_match`). - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \ - used as the type of a const parameter", - ty, - ) - .span_label( - hir_ty.span, - format!("`{}` may not derive both `PartialEq` and `Eq`", ty), - ) - .note( - "it is not currently possible to use a type parameter as the type of a \ - const parameter", - ) - .emit(); - } else { - let mut diag = struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ - the type of a const parameter", - non_structural_match_ty.ty, - ); - - if ty == non_structural_match_ty.ty { - diag.span_label( + match ty.peel_refs().kind() { + ty::Param(_) => { + // Const parameters may not have type parameters as their types, + // because we cannot be sure that the type parameter derives `PartialEq` + // and `Eq` (just implementing them is not enough for `structural_match`). + struct_span_err!( + tcx.sess, hir_ty.span, - format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), - ); + E0741, + "`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \ + used as the type of a const parameter", + ) + .span_label( + hir_ty.span, + format!("`{ty}` may not derive both `PartialEq` and `Eq`"), + ) + .note( + "it is not currently possible to use a type parameter as the type of a \ + const parameter", + ) + .emit(); + } + ty::Float(_) => { + struct_span_err!( + tcx.sess, + hir_ty.span, + E0741, + "`{ty}` is forbidden as the type of a const generic parameter", + ) + .note("floats do not derive `Eq` or `Ord`, which are required for const parameters") + .emit(); } + _ => { + let mut diag = struct_span_err!( + tcx.sess, + hir_ty.span, + E0741, + "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ + the type of a const parameter", + non_structural_match_ty.ty, + ); + + if ty == non_structural_match_ty.ty { + diag.span_label( + hir_ty.span, + format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), + ); + } - diag.emit(); + diag.emit(); + } } } } else { @@ -907,45 +974,45 @@ fn check_associated_item( span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))); - for_id(tcx, item_id, span).with_fcx(|fcx| { - let item = fcx.tcx.associated_item(item_id); + let loc = Some(WellFormedLoc::Ty(item_id)); + enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { + let item = tcx.associated_item(item_id); let (mut implied_bounds, self_ty) = match item.container { - ty::TraitContainer(_) => (FxHashSet::default(), fcx.tcx.types.self_param), - ty::ImplContainer(def_id) => { - (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id)) - } + ty::TraitContainer(_) => (FxHashSet::default(), tcx.types.self_param), + ty::ImplContainer(def_id) => ( + impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span), + tcx.type_of(def_id), + ), }; match item.kind { ty::AssocKind::Const => { - let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); - fcx.register_wf_obligation(ty.into(), span, code.clone()); + let ty = tcx.type_of(item.def_id); + let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + wfcx.register_wf_obligation(span, loc, ty.into()); } ty::AssocKind::Fn => { - let sig = fcx.tcx.fn_sig(item.def_id); + let sig = tcx.fn_sig(item.def_id); let hir_sig = sig_if_method.expect("bad signature for method"); check_fn_or_method( - fcx, - item.ident(fcx.tcx).span, + wfcx, + item.ident(tcx).span, sig, hir_sig.decl, item.def_id.expect_local(), &mut implied_bounds, ); - check_method_receiver(fcx, hir_sig, item, self_ty); + check_method_receiver(wfcx, hir_sig, item, self_ty); } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer(_) = item.container { - check_associated_type_bounds(fcx, item, span) + check_associated_type_bounds(wfcx, item, span) } if item.defaultness.has_value() { - let ty = fcx.tcx.type_of(item.def_id); - let ty = - fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id)); - fcx.register_wf_obligation(ty.into(), span, code.clone()); + let ty = tcx.type_of(item.def_id); + let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + wfcx.register_wf_obligation(span, loc, ty.into()); } } } @@ -954,19 +1021,6 @@ fn check_associated_item( }) } -pub(super) fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> { - for_id(tcx, item.def_id, item.span) -} - -fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> { - CheckWfFcxBuilder { - inherited: Inherited::build(tcx, def_id), - id: hir::HirId::make_owner(def_id), - span, - param_env: tcx.param_env(def_id), - } -} - fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> { match kind { ItemKind::Struct(..) => Some(AdtKind::Struct), @@ -983,13 +1037,22 @@ fn check_type_defn<'tcx, F>( all_sized: bool, mut lookup_fields: F, ) where - F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>, + F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>, { - for_item(tcx, item).with_fcx(|fcx| { - let variants = lookup_fields(fcx); + enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { + let variants = lookup_fields(wfcx); let packed = tcx.adt_def(item.def_id).repr().packed(); for variant in &variants { + // All field types must be well-formed. + for field in &variant.fields { + wfcx.register_wf_obligation( + field.span, + Some(WellFormedLoc::Ty(field.def_id)), + field.ty.into(), + ) + } + // For DST, or when drop needs to copy things around, all // intermediate types must be sized. let needs_drop_copy = || { @@ -1006,18 +1069,17 @@ fn check_type_defn<'tcx, F>( } } }; + // All fields (except for possibly the last) should be sized. let all_sized = all_sized || variant.fields.is_empty() || needs_drop_copy(); let unsized_len = if all_sized { 0 } else { 1 }; for (idx, field) in variant.fields[..variant.fields.len() - unsized_len].iter().enumerate() { let last = idx == variant.fields.len() - 1; - fcx.register_bound( - field.ty, - tcx.require_lang_item(LangItem::Sized, None), + wfcx.register_bound( traits::ObligationCause::new( field.span, - fcx.body_id, + wfcx.body_id, traits::FieldSized { adt_kind: match item_adt_kind(&item.kind) { Some(i) => i, @@ -1027,30 +1089,24 @@ fn check_type_defn<'tcx, F>( last, }, ), + wfcx.param_env, + field.ty, + tcx.require_lang_item(LangItem::Sized, None), ); } - // All field types must be well-formed. - for field in &variant.fields { - fcx.register_wf_obligation( - field.ty.into(), - field.span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(field.def_id))), - ) - } - // Explicit `enum` discriminant values must const-evaluate successfully. if let Some(discr_def_id) = variant.explicit_discr { let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id()); let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), - fcx.body_id, + wfcx.body_id, traits::MiscObligation, ); - fcx.register_predicate(traits::Obligation::new( + wfcx.register_obligation(traits::Obligation::new( cause, - fcx.param_env, + wfcx.param_env, ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, @@ -1060,7 +1116,7 @@ fn check_type_defn<'tcx, F>( } } - check_where_clauses(fcx, item.span, item.def_id, None); + check_where_clauses(wfcx, item.span, item.def_id); // No implied bounds in a struct definition. FxHashSet::default() @@ -1086,9 +1142,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { } } - // FIXME: this shouldn't use an `FnCtxt` at all. - for_item(tcx, item).with_fcx(|fcx| { - check_where_clauses(fcx, item.span, item.def_id, None); + enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { + check_where_clauses(wfcx, item.span, item.def_id); FxHashSet::default() }); @@ -1103,27 +1158,22 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { /// /// Assuming the defaults are used, check that all predicates (bounds on the /// assoc type and where clauses on the trait) hold. -fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span: Span) { - let tcx = fcx.tcx; - - let bounds = tcx.explicit_item_bounds(item.def_id); +fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: &ty::AssocItem, span: Span) { + let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let normalized_bound = fcx.normalize_associated_types_in(span, bound); + let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( - fcx, - fcx.param_env, - fcx.body_id, + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, normalized_bound, bound_span, ) }); - for obligation in wf_obligations { - debug!("next obligation cause: {:?}", obligation.cause); - fcx.register_predicate(obligation); - } + wfcx.register_obligations(wf_obligations); } fn check_item_fn( @@ -1133,10 +1183,10 @@ fn check_item_fn( span: Span, decl: &hir::FnDecl<'_>, ) { - for_id(tcx, def_id, span).with_fcx(|fcx| { + enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { let sig = tcx.fn_sig(def_id); let mut implied_bounds = FxHashSet::default(); - check_fn_or_method(fcx, ident.span, sig, decl, def_id, &mut implied_bounds); + check_fn_or_method(wfcx, ident.span, sig, decl, def_id, &mut implied_bounds); implied_bounds }) } @@ -1144,28 +1194,25 @@ fn check_item_fn( fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) { debug!("check_item_type: {:?}", item_id); - for_id(tcx, item_id, ty_span).with_fcx(|fcx| { + enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id); - let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, WellFormedLoc::Ty(item_id)); + let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); let mut forbid_unsized = true; if allow_foreign_ty { - let tail = fcx.tcx.struct_tail_erasing_lifetimes(item_ty, fcx.param_env); + let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env); if let ty::Foreign(_) = tail.kind() { forbid_unsized = false; } } - fcx.register_wf_obligation( - item_ty.into(), - ty_span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))), - ); + wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { - fcx.register_bound( + wfcx.register_bound( + traits::ObligationCause::new(ty_span, wfcx.body_id, traits::WellFormed(None)), + wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sized, None), - traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation), ); } @@ -1176,10 +1223,11 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo && !tcx.is_thread_local_static(item_id.to_def_id()); if should_check_for_sync { - fcx.register_bound( + wfcx.register_bound( + traits::ObligationCause::new(ty_span, wfcx.body_id, traits::SharedStatic), + wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sync, Some(ty_span)), - traits::ObligationCause::new(ty_span, fcx.body_id, traits::SharedStatic), ); } @@ -1195,56 +1243,47 @@ fn check_impl<'tcx>( ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option<hir::TraitRef<'_>>, ) { - for_item(tcx, item).with_fcx(|fcx| { + enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { match *ast_trait_ref { Some(ref ast_trait_ref) => { // `#[rustc_reservation_impl]` impls are not real impls and // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap(); - let trait_ref = - fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref); + let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); let obligations = traits::wf::trait_obligations( - fcx, - fcx.param_env, - fcx.body_id, + wfcx.infcx, + wfcx.param_env, + wfcx.body_id, &trait_ref, ast_trait_ref.path.span, item, ); debug!(?obligations); - for obligation in obligations { - fcx.register_predicate(obligation); - } + wfcx.register_obligations(obligations); } None => { let self_ty = tcx.type_of(item.def_id); - let self_ty = fcx.normalize_associated_types_in(item.span, self_ty); - fcx.register_wf_obligation( - self_ty.into(), + let self_ty = wfcx.normalize(item.span, None, self_ty); + wfcx.register_wf_obligation( ast_self_ty.span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty( - item.hir_id().expect_owner(), - ))), + Some(WellFormedLoc::Ty(item.hir_id().expect_owner())), + self_ty.into(), ); } } - check_where_clauses(fcx, item.span, item.def_id, None); + check_where_clauses(wfcx, item.span, item.def_id); - fcx.impl_implied_bounds(item.def_id.to_def_id(), item.span) + impl_implied_bounds(tcx, wfcx.param_env, item.def_id, item.span) }); } /// Checks where-clauses and inline bounds that are declared on `def_id`. -#[instrument(skip(fcx), level = "debug")] -fn check_where_clauses<'tcx, 'fcx>( - fcx: &FnCtxt<'fcx, 'tcx>, - span: Span, - def_id: LocalDefId, - return_ty: Option<(Ty<'tcx>, Span)>, -) { - let tcx = fcx.tcx; +#[instrument(level = "debug", skip(wfcx))] +fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id: LocalDefId) { + let infcx = wfcx.infcx; + let tcx = wfcx.tcx(); let predicates = tcx.predicates_of(def_id); let generics = tcx.generics_of(def_id); @@ -1272,11 +1311,7 @@ fn check_where_clauses<'tcx, 'fcx>( // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { - fcx.register_wf_obligation( - ty.into(), - tcx.def_span(param.def_id), - ObligationCauseCode::MiscObligation, - ); + wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into()); } } } @@ -1288,10 +1323,10 @@ fn check_where_clauses<'tcx, 'fcx>( // we should eagerly error. let default_ct = tcx.const_param_default(param.def_id); if !default_ct.needs_subst() { - fcx.register_wf_obligation( - default_ct.into(), + wfcx.register_wf_obligation( tcx.def_span(param.def_id), - ObligationCauseCode::WellFormed(None), + None, + default_ct.into(), ); } } @@ -1354,7 +1389,7 @@ fn check_where_clauses<'tcx, 'fcx>( struct CountParams { params: FxHashSet<u32>, } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { + impl<'tcx> ty::visit::TypeVisitor<'tcx> for CountParams { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -1402,48 +1437,41 @@ fn check_where_clauses<'tcx, 'fcx>( // Note the subtle difference from how we handle `predicates` // below: there, we are not trying to prove those predicates // to be *true* but merely *well-formed*. - let pred = fcx.normalize_associated_types_in(sp, pred); + let pred = wfcx.normalize(sp, None, pred); let cause = traits::ObligationCause::new( sp, - fcx.body_id, + wfcx.body_id, traits::ItemObligation(def_id.to_def_id()), ); - traits::Obligation::new(cause, fcx.param_env, pred) + traits::Obligation::new(cause, wfcx.param_env, pred) }); let predicates = predicates.instantiate_identity(tcx); - if let Some((return_ty, _)) = return_ty { - if return_ty.has_infer_types_or_consts() { - fcx.select_obligations_where_possible(false, |_| {}); - } - } - - let predicates = fcx.normalize_associated_types_in(span, predicates); + let predicates = wfcx.normalize(span, None, predicates); debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { - traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, sp) + traits::wf::predicate_obligations(infcx, wfcx.param_env, wfcx.body_id, p, sp) }); - for obligation in wf_obligations.chain(default_obligations) { - debug!("next obligation cause: {:?}", obligation.cause); - fcx.register_predicate(obligation); - } + let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); + wfcx.register_obligations(obligations); } -#[tracing::instrument(level = "debug", skip(fcx, span, hir_decl))] -fn check_fn_or_method<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, +#[tracing::instrument(level = "debug", skip(wfcx, span, hir_decl))] +fn check_fn_or_method<'tcx>( + wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, hir_decl: &hir::FnDecl<'_>, def_id: LocalDefId, implied_bounds: &mut FxHashSet<Ty<'tcx>>, ) { - let sig = fcx.tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + let tcx = wfcx.tcx(); + let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` @@ -1451,70 +1479,61 @@ fn check_fn_or_method<'fcx, 'tcx>( // for each type, preventing the HIR wf check from generating // a nice error message. let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig; - inputs_and_output = - fcx.tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { - fcx.normalize_associated_types_in_wf( - span, - ty, - WellFormedLoc::Param { - function: def_id, - // Note that the `param_idx` of the output type is - // one greater than the index of the last input type. - param_idx: i.try_into().unwrap(), - }, - ) - })); + inputs_and_output = tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { + wfcx.normalize( + span, + Some(WellFormedLoc::Param { + function: def_id, + // Note that the `param_idx` of the output type is + // one greater than the index of the last input type. + param_idx: i.try_into().unwrap(), + }), + ty, + ) + })); // Manually call `normalize_associated_types_in` on the other types // in `FnSig`. This ensures that if the types of these fields // ever change to include projections, we will start normalizing // them automatically. let sig = ty::FnSig { inputs_and_output, - c_variadic: fcx.normalize_associated_types_in(span, c_variadic), - unsafety: fcx.normalize_associated_types_in(span, unsafety), - abi: fcx.normalize_associated_types_in(span, abi), + c_variadic: wfcx.normalize(span, None, c_variadic), + unsafety: wfcx.normalize(span, None, unsafety), + abi: wfcx.normalize(span, None, abi), }; for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() { - fcx.register_wf_obligation( - input_ty.into(), + wfcx.register_wf_obligation( ty.span, - ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param { - function: def_id, - param_idx: i.try_into().unwrap(), - })), + Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }), + input_ty.into(), ); } implied_bounds.extend(sig.inputs()); - fcx.register_wf_obligation( - sig.output().into(), - hir_decl.output.span(), - ObligationCauseCode::ReturnType, - ); + wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into()); // FIXME(#27579) return types should not be implied bounds implied_bounds.insert(sig.output()); debug!(?implied_bounds); - check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span()))); + check_where_clauses(wfcx, span, def_id); } const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \ `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \ of the previous types except `Self`)"; -#[tracing::instrument(level = "debug", skip(fcx))] -fn check_method_receiver<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, +#[tracing::instrument(level = "debug", skip(wfcx))] +fn check_method_receiver<'tcx>( + wfcx: &WfCheckingCtxt<'_, 'tcx>, fn_sig: &hir::FnSig<'_>, method: &ty::AssocItem, self_ty: Ty<'tcx>, ) { - // Check that the method has a valid receiver type, given the type `Self`. - debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); + let tcx = wfcx.tcx(); if !method.fn_has_self_parameter { return; @@ -1522,28 +1541,28 @@ fn check_method_receiver<'fcx, 'tcx>( let span = fn_sig.decl.inputs[0].span; - let sig = fcx.tcx.fn_sig(method.def_id); - let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig); - let sig = fcx.normalize_associated_types_in(span, sig); + let sig = tcx.fn_sig(method.def_id); + let sig = tcx.liberate_late_bound_regions(method.def_id, sig); + let sig = wfcx.normalize(span, None, sig); debug!("check_method_receiver: sig={:?}", sig); - let self_ty = fcx.normalize_associated_types_in(span, self_ty); + let self_ty = wfcx.normalize(span, None, self_ty); let receiver_ty = sig.inputs()[0]; - let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty); + let receiver_ty = wfcx.normalize(span, None, receiver_ty); - if fcx.tcx.features().arbitrary_self_types { - if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { + if tcx.features().arbitrary_self_types { + if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. - e0307(fcx, span, receiver_ty); + e0307(tcx, span, receiver_ty); } } else { - if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) { - if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { + if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { + if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; would have worked with `arbitrary_self_types`. feature_err( - &fcx.tcx.sess.parse_sess, + &tcx.sess.parse_sess, sym::arbitrary_self_types, span, &format!( @@ -1555,15 +1574,15 @@ fn check_method_receiver<'fcx, 'tcx>( .emit(); } else { // Report error; would not have worked with `arbitrary_self_types`. - e0307(fcx, span, receiver_ty); + e0307(tcx, span, receiver_ty); } } } } -fn e0307<'tcx>(fcx: &FnCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'_>) { +fn e0307<'tcx>(tcx: TyCtxt<'tcx>, span: Span, receiver_ty: Ty<'_>) { struct_span_err!( - fcx.tcx.sess.diagnostic(), + tcx.sess.diagnostic(), span, E0307, "invalid `self` parameter type: {receiver_ty}" @@ -1582,26 +1601,30 @@ fn e0307<'tcx>(fcx: &FnCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'_>) { /// N.B., there are cases this function returns `true` but causes an error to be emitted, /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the /// wrong lifetime. Be careful of this if you are calling this function speculatively. -fn receiver_is_valid<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, +fn receiver_is_valid<'tcx>( + wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: bool, ) -> bool { - let cause = fcx.cause(span, traits::ObligationCauseCode::MethodReceiver); + let infcx = wfcx.infcx; + let tcx = wfcx.tcx(); + let cause = + ObligationCause::new(span, wfcx.body_id, traits::ObligationCauseCode::MethodReceiver); - let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); + let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty).is_ok(); // `self: Self` is always valid. if can_eq_self(receiver_ty) { - if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) { - err.emit(); + if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) { + infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); } return true; } - let mut autoderef = fcx.autoderef(span, receiver_ty); + let mut autoderef = + Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty, span); // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. if arbitrary_self_types_enabled { @@ -1611,7 +1634,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. autoderef.next(); - let receiver_trait_def_id = fcx.tcx.require_lang_item(LangItem::Receiver, None); + let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, None); // Keep dereferencing `receiver_ty` until we get to `self_ty`. loop { @@ -1622,12 +1645,12 @@ fn receiver_is_valid<'fcx, 'tcx>( ); if can_eq_self(potential_self_ty) { - fcx.register_predicates(autoderef.into_obligations()); + wfcx.register_obligations(autoderef.into_obligations()); - if let Some(mut err) = - fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) + if let Err(err) = + wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty) { - err.emit(); + infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit(); } break; @@ -1636,7 +1659,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // deref chain implement `receiver` if !arbitrary_self_types_enabled && !receiver_is_implemented( - fcx, + wfcx, receiver_trait_def_id, cause.clone(), potential_self_ty, @@ -1655,7 +1678,7 @@ fn receiver_is_valid<'fcx, 'tcx>( // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. if !arbitrary_self_types_enabled - && !receiver_is_implemented(fcx, receiver_trait_def_id, cause.clone(), receiver_ty) + && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty) { return false; } @@ -1664,23 +1687,21 @@ fn receiver_is_valid<'fcx, 'tcx>( } fn receiver_is_implemented<'tcx>( - fcx: &FnCtxt<'_, 'tcx>, + wfcx: &WfCheckingCtxt<'_, 'tcx>, receiver_trait_def_id: DefId, cause: ObligationCause<'tcx>, receiver_ty: Ty<'tcx>, ) -> bool { + let tcx = wfcx.tcx(); let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: receiver_trait_def_id, - substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), + substs: tcx.mk_substs_trait(receiver_ty, &[]), }); - let obligation = traits::Obligation::new( - cause, - fcx.param_env, - trait_ref.without_const().to_predicate(fcx.tcx), - ); + let obligation = + traits::Obligation::new(cause, wfcx.param_env, trait_ref.without_const().to_predicate(tcx)); - if fcx.predicate_must_hold_modulo_regions(&obligation) { + if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) { true } else { debug!( @@ -1782,112 +1803,64 @@ fn report_bivariance( err.emit() } -/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that -/// aren't true. -fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirId) { - let empty_env = ty::ParamEnv::empty(); - - let def_id = fcx.tcx.hir().local_def_id(id); - let predicates_with_span = - fcx.tcx.predicates_of(def_id).predicates.iter().map(|(p, span)| (*p, *span)); - // Check elaborated bounds. - let implied_obligations = traits::elaborate_predicates_with_span(fcx.tcx, predicates_with_span); +impl<'tcx> WfCheckingCtxt<'_, 'tcx> { + /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that + /// aren't true. + fn check_false_global_bounds(&mut self) { + let tcx = self.ocx.infcx.tcx; + let mut span = self.span; + let empty_env = ty::ParamEnv::empty(); + + let def_id = tcx.hir().local_def_id(self.body_id); + let predicates_with_span = tcx.predicates_of(def_id).predicates.iter().copied(); + // Check elaborated bounds. + let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); + + for obligation in implied_obligations { + // We lower empty bounds like `Vec<dyn Copy>:` as + // `WellFormed(Vec<dyn Copy>)`, which will later get checked by + // regular WF checking + if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() { + continue; + } + let pred = obligation.predicate; + // Match the existing behavior. + if pred.is_global() && !pred.has_late_bound_regions() { + let pred = self.normalize(span, None, pred); + let hir_node = tcx.hir().find(self.body_id); - for obligation in implied_obligations { - let pred = obligation.predicate; - // Match the existing behavior. - if pred.is_global() && !pred.has_late_bound_regions() { - let pred = fcx.normalize_associated_types_in(span, pred); - let hir_node = fcx.tcx.hir().find(id); + // only use the span of the predicate clause (#90869) - // only use the span of the predicate clause (#90869) + if let Some(hir::Generics { predicates, .. }) = + hir_node.and_then(|node| node.generics()) + { + let obligation_span = obligation.cause.span(); + + span = predicates + .iter() + // There seems to be no better way to find out which predicate we are in + .find(|pred| pred.span().contains(obligation_span)) + .map(|pred| pred.span()) + .unwrap_or(obligation_span); + } - if let Some(hir::Generics { predicates, .. }) = - hir_node.and_then(|node| node.generics()) - { - let obligation_span = obligation.cause.span(fcx.tcx); - - span = predicates - .iter() - // There seems to be no better way to find out which predicate we are in - .find(|pred| pred.span().contains(obligation_span)) - .map(|pred| pred.span()) - .unwrap_or(obligation_span); + let obligation = traits::Obligation::new( + traits::ObligationCause::new(span, self.body_id, traits::TrivialBound), + empty_env, + pred, + ); + self.ocx.register_obligation(obligation); } - - let obligation = traits::Obligation::new( - traits::ObligationCause::new(span, id, traits::TrivialBound), - empty_env, - pred, - ); - fcx.register_predicate(obligation); } } - - fcx.select_all_obligations_or_error(); -} - -#[derive(Clone, Copy)] -pub struct CheckTypeWellFormedVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> CheckTypeWellFormedVisitor<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> CheckTypeWellFormedVisitor<'tcx> { - CheckTypeWellFormedVisitor { tcx } - } } -impl<'tcx> ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { - fn visit_item(&self, i: &'tcx hir::Item<'tcx>) { - Visitor::visit_item(&mut self.clone(), i); - } - - fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) { - Visitor::visit_trait_item(&mut self.clone(), trait_item); - } - - fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) { - Visitor::visit_impl_item(&mut self.clone(), impl_item); - } - - fn visit_foreign_item(&self, foreign_item: &'tcx hir::ForeignItem<'tcx>) { - Visitor::visit_foreign_item(&mut self.clone(), foreign_item) - } -} - -impl<'tcx> Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - - #[instrument(skip(self, i), level = "debug")] - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - trace!(?i); - self.tcx.ensure().check_item_well_formed(i.def_id); - hir_visit::walk_item(self, i); - } - - #[instrument(skip(self, trait_item), level = "debug")] - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - trace!(?trait_item); - self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id); - hir_visit::walk_trait_item(self, trait_item); - } - - #[instrument(skip(self, impl_item), level = "debug")] - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - trace!(?impl_item); - self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id); - hir_visit::walk_impl_item(self, impl_item); - } - - fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - check_param_wf(self.tcx, p); - hir_visit::walk_generic_param(self, p); - } +fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) { + let items = tcx.hir_module_items(module); + items.par_items(|item| tcx.ensure().check_well_formed(item.def_id)); + items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id)); + items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id)); + items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id)); } /////////////////////////////////////////////////////////////////////////// @@ -1909,17 +1882,16 @@ struct AdtField<'tcx> { span: Span, } -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> { // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`. fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> { let fields = struct_def .fields() .iter() .map(|field| { - let def_id = self.tcx.hir().local_def_id(field.hir_id); - let field_ty = self.tcx.type_of(def_id); - let field_ty = self.normalize_associated_types_in(field.ty.span, field_ty); - let field_ty = self.resolve_vars_if_possible(field_ty); + let def_id = self.tcx().hir().local_def_id(field.hir_id); + let field_ty = self.tcx().type_of(def_id); + let field_ty = self.normalize(field.ty.span, None, field_ty); debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); AdtField { ty: field_ty, span: field.ty.span, def_id } }) @@ -1935,32 +1907,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: self.non_enum_variant(&variant.data).fields, explicit_discr: variant .disr_expr - .map(|explicit_discr| self.tcx.hir().local_def_id(explicit_discr.hir_id)), + .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)), }) .collect() } +} - pub(super) fn impl_implied_bounds( - &self, - impl_def_id: DefId, - span: Span, - ) -> FxHashSet<Ty<'tcx>> { - match self.tcx.impl_trait_ref(impl_def_id) { +pub(super) fn impl_implied_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: LocalDefId, + span: Span, +) -> FxHashSet<Ty<'tcx>> { + // We completely ignore any obligations caused by normalizing the types + // we assume to be well formed. Considering that the user of the implied + // bounds will also normalize them, we leave it to them to emit errors + // which should result in better causes and spans. + tcx.infer_ctxt().enter(|infcx| { + let cause = ObligationCause::misc(span, tcx.hir().local_def_id_to_hir_id(impl_def_id)); + match tcx.impl_trait_ref(impl_def_id) { Some(trait_ref) => { // Trait impl: take implied bounds from all types that // appear in the trait reference. - let trait_ref = self.normalize_associated_types_in(span, trait_ref); - trait_ref.substs.types().collect() + match infcx.at(&cause, param_env).normalize(trait_ref) { + Ok(Normalized { value, obligations: _ }) => value.substs.types().collect(), + Err(NoSolution) => FxHashSet::default(), + } } None => { // Inherent impl: take implied bounds from the `self` type. - let self_ty = self.tcx.type_of(impl_def_id); - let self_ty = self.normalize_associated_types_in(span, self_ty); - FxHashSet::from_iter([self_ty]) + let self_ty = tcx.type_of(impl_def_id); + match infcx.at(&cause, param_env).normalize(self_ty) { + Ok(Normalized { value, obligations: _ }) => FxHashSet::from_iter([value]), + Err(NoSolution) => FxHashSet::default(), + } } } - } + }) } fn error_392( @@ -1972,3 +1956,7 @@ fn error_392( err.span_label(span, "unused parameter"); err } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers }; +} diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 9459cf5f8ca80..0cbb0e25d0d42 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -15,6 +15,7 @@ use rustc_middle::hir::place::Place as HirPlace; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -262,7 +263,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.fix_index_builtin_expr(e); match e.kind { - hir::ExprKind::Closure { body, .. } => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = self.fcx.tcx.hir().body(body); for param in body.params { self.visit_node_id(e.span, param.hir_id); @@ -692,8 +693,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { Some(self.body.id()), self.span.to_span(self.tcx), t.into(), - vec![], E0282, + false, ) .emit(); } @@ -706,8 +707,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { Some(self.body.id()), self.span.to_span(self.tcx), c.into(), - vec![], E0282, + false, ) .emit(); } diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index c647c2a4c1baa..a92c37ff143b4 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -11,7 +11,7 @@ use rustc_infer::infer; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; -use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; use rustc_trait_selection::traits::predicate_for_trait_def; @@ -349,7 +349,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - infcx.resolve_regions_and_report_errors(impl_did.to_def_id(), &outlives_env); + infcx.resolve_regions_and_report_errors(impl_did, &outlives_env); } } _ => { @@ -606,7 +606,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn // Finally, resolve all regions. let outlives_env = OutlivesEnvironment::new(param_env); - infcx.resolve_regions_and_report_errors(impl_did.to_def_id(), &outlives_env); + infcx.resolve_regions_and_report_errors(impl_did, &outlives_env); CoerceUnsizedInfo { custom_kind: kind } }) diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index db67c1f7c9ed3..03e076bf5ec89 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -76,17 +76,17 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let name = item1.ident(self.tcx).normalize_to_macros_2_0(); let mut err = struct_span_err!( self.tcx.sess, - self.tcx.span_of_impl(item1.def_id).unwrap(), + self.tcx.def_span(item1.def_id), E0592, "duplicate definitions with name `{}`", name ); err.span_label( - self.tcx.span_of_impl(item1.def_id).unwrap(), + self.tcx.def_span(item1.def_id), format!("duplicate definitions for `{}`", name), ); err.span_label( - self.tcx.span_of_impl(item2.def_id).unwrap(), + self.tcx.def_span(item2.def_id), format!("other definition for `{}`", name), ); diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs index 3903448a00731..ae9ebe5909144 100644 --- a/compiler/rustc_typeck/src/coherence/mod.rs +++ b/compiler/rustc_typeck/src/coherence/mod.rs @@ -8,8 +8,7 @@ use rustc_errors::struct_span_err; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; -use rustc_span::Span; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_trait_selection::traits; mod builtin; @@ -18,11 +17,6 @@ mod inherent_impls_overlap; mod orphan; mod unsafety; -/// Obtains the span of just the impl header of `impl_def_id`. -fn impl_header_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span { - tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id.to_def_id()).unwrap()) -} - fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<'_>) { debug!( "(checking implementation) adding impl for trait '{:?}', item '{}'", @@ -47,56 +41,53 @@ fn enforce_trait_manually_implementable( ) { let did = Some(trait_def_id); let li = tcx.lang_items(); + let impl_header_span = tcx.def_span(impl_def_id); // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now. if did == li.pointee_trait() { - let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, - span, + impl_header_span, E0322, "explicit impls for the `Pointee` trait are not permitted" ) - .span_label(span, "impl of `Pointee` not allowed") + .span_label(impl_header_span, "impl of `Pointee` not allowed") .emit(); return; } if did == li.discriminant_kind_trait() { - let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, - span, + impl_header_span, E0322, "explicit impls for the `DiscriminantKind` trait are not permitted" ) - .span_label(span, "impl of `DiscriminantKind` not allowed") + .span_label(impl_header_span, "impl of `DiscriminantKind` not allowed") .emit(); return; } if did == li.sized_trait() { - let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, - span, + impl_header_span, E0322, "explicit impls for the `Sized` trait are not permitted" ) - .span_label(span, "impl of `Sized` not allowed") + .span_label(impl_header_span, "impl of `Sized` not allowed") .emit(); return; } if did == li.unsize_trait() { - let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, - span, + impl_header_span, E0328, "explicit impls for the `Unsize` trait are not permitted" ) - .span_label(span, "impl of `Unsize` not allowed") + .span_label(impl_header_span, "impl of `Unsize` not allowed") .emit(); return; } @@ -110,10 +101,9 @@ fn enforce_trait_manually_implementable( tcx.trait_def(trait_def_id).specialization_kind { if !tcx.features().specialization && !tcx.features().min_specialization { - let span = impl_header_span(tcx, impl_def_id); tcx.sess .struct_span_err( - span, + impl_header_span, "implementing `rustc_specialization_trait` traits is unstable", ) .help("add `#![feature(min_specialization)]` to the crate attributes to enable") @@ -138,15 +128,20 @@ fn enforce_empty_impls_for_marker_traits( return; } - let span = impl_header_span(tcx, impl_def_id); - struct_span_err!(tcx.sess, span, E0715, "impls for marker traits cannot contain items").emit(); + struct_span_err!( + tcx.sess, + tcx.def_span(impl_def_id), + E0715, + "impls for marker traits cannot contain items" + ) + .emit(); } pub fn provide(providers: &mut Providers) { use self::builtin::coerce_unsized_info; use self::inherent_impls::{crate_incoherent_impls, crate_inherent_impls, inherent_impls}; use self::inherent_impls_overlap::crate_inherent_impls_overlap_check; - use self::orphan::orphan_check_crate; + use self::orphan::orphan_check_impl; *providers = Providers { coherent_trait, @@ -155,7 +150,7 @@ pub fn provide(providers: &mut Providers) { inherent_impls, crate_inherent_impls_overlap_check, coerce_unsized_info, - orphan_check_crate, + orphan_check_impl, ..*providers }; } @@ -171,21 +166,12 @@ 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); - } - builtin::check_trait(tcx, def_id); -} - -pub fn check_coherence(tcx: TyCtxt<'_>) { - tcx.sess.time("unsafety_checking", || unsafety::check(tcx)); - tcx.ensure().orphan_check_crate(()); - for &trait_def_id in tcx.all_local_trait_impls(()).keys() { - tcx.ensure().coherent_trait(trait_def_id); + 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)); } - // these queries are executed for side-effects (error reporting): - tcx.ensure().crate_inherent_impls(()); - tcx.ensure().crate_inherent_impls_overlap_check(()); + builtin::check_trait(tcx, def_id); } /// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`. @@ -226,7 +212,7 @@ fn check_object_overlap<'tcx>( } else { let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids.any(|d| d == trait_def_id) { - let span = impl_header_span(tcx, impl_def_id); + let span = tcx.def_span(impl_def_id); struct_span_err!( tcx.sess, span, diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 9ddfc8d5cc82b..697ef7bc02237 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IgnoreRegions; use rustc_middle::ty::{ - self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor, + self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_session::lint; use rustc_span::def_id::{DefId, LocalDefId}; @@ -18,33 +18,36 @@ use rustc_span::Span; use rustc_trait_selection::traits; use std::ops::ControlFlow; -pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] { - let mut errors = Vec::new(); - for (&trait_def_id, impls_of_trait) in tcx.all_local_trait_impls(()) { - for &impl_of_trait in impls_of_trait { - match orphan_check_impl(tcx, impl_of_trait) { - Ok(()) => {} - Err(_) => errors.push(impl_of_trait), - } - } +#[instrument(skip(tcx), level = "debug")] +pub(crate) fn orphan_check_impl( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if let Some(err) = trait_ref.error_reported() { + return Err(err); + } - if tcx.trait_is_auto(trait_def_id) { - lint_auto_trait_impls(tcx, trait_def_id, impls_of_trait); - } + let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id); + if tcx.trait_is_auto(trait_ref.def_id) { + lint_auto_trait_impl(tcx, trait_ref, impl_def_id); } - tcx.arena.alloc_slice(&errors) + + ret } -#[instrument(skip(tcx), level = "debug")] -fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { - let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); +fn do_orphan_check_impl<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { let trait_def_id = trait_ref.def_id; let item = tcx.hir().item(hir::ItemId { def_id }); let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!("{:?} is not an impl: {:?}", def_id, item); }; - let sp = tcx.sess.source_map().guess_head_span(item.span); + let sp = tcx.def_span(def_id); let tr = impl_.of_trait.as_ref().unwrap(); // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples, @@ -329,89 +332,82 @@ fn emit_orphan_check_error<'tcx>( /// Lint impls of auto traits if they are likely to have /// unsound or surprising effects on auto impls. -fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDefId]) { - let mut non_covering_impls = Vec::new(); - for &impl_def_id in impls { - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - if trait_ref.references_error() { - return; - } +fn lint_auto_trait_impl<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + impl_def_id: LocalDefId, +) { + if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive { + return; + } - if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive { + assert_eq!(trait_ref.substs.len(), 1); + let self_ty = trait_ref.self_ty(); + let (self_type_did, substs) = match self_ty.kind() { + ty::Adt(def, substs) => (def.did(), substs), + _ => { + // FIXME: should also lint for stuff like `&i32` but + // considering that auto traits are unstable, that + // isn't too important for now as this only affects + // crates using `nightly`, and std. return; } + }; - assert_eq!(trait_ref.substs.len(), 1); - let self_ty = trait_ref.self_ty(); - let (self_type_did, substs) = match self_ty.kind() { - ty::Adt(def, substs) => (def.did(), substs), - _ => { - // FIXME: should also lint for stuff like `&i32` but - // considering that auto traits are unstable, that - // isn't too important for now as this only affects - // crates using `nightly`, and std. - continue; - } - }; + // Impls which completely cover a given root type are fine as they + // disable auto impls entirely. So only lint if the substs + // are not a permutation of the identity substs. + let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else { + // ok + return; + }; - // Impls which completely cover a given root type are fine as they - // disable auto impls entirely. So only lint if the substs - // are not a permutation of the identity substs. - match tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) { - Ok(()) => {} // ok - Err(arg) => { - // Ideally: - // - // - compute the requirements for the auto impl candidate - // - check whether these are implied by the non covering impls - // - if not, emit the lint - // - // What we do here is a bit simpler: - // - // - badly check if an auto impl candidate definitely does not apply - // for the given simplified type - // - if so, do not lint - if fast_reject_auto_impl(tcx, trait_def_id, self_ty) { - // ok - } else { - non_covering_impls.push((impl_def_id, self_type_did, arg)); - } - } - } + // Ideally: + // + // - compute the requirements for the auto impl candidate + // - check whether these are implied by the non covering impls + // - if not, emit the lint + // + // What we do here is a bit simpler: + // + // - badly check if an auto impl candidate definitely does not apply + // for the given simplified type + // - if so, do not lint + if fast_reject_auto_impl(tcx, trait_ref.def_id, self_ty) { + // ok + return; } - for &(impl_def_id, self_type_did, arg) in &non_covering_impls { - tcx.struct_span_lint_hir( - lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, - tcx.hir().local_def_id_to_hir_id(impl_def_id), - tcx.def_span(impl_def_id), - |err| { - let item_span = tcx.def_span(self_type_did); - let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); - let mut err = err.build(&format!( - "cross-crate traits with a default impl, like `{}`, \ + tcx.struct_span_lint_hir( + lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, + tcx.hir().local_def_id_to_hir_id(impl_def_id), + tcx.def_span(impl_def_id), + |err| { + let item_span = tcx.def_span(self_type_did); + let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); + let mut err = err.build(&format!( + "cross-crate traits with a default impl, like `{}`, \ should not be specialized", - tcx.def_path_str(trait_def_id), - )); - match arg { - ty::util::NotUniqueParam::DuplicateParam(arg) => { - err.note(&format!("`{}` is mentioned multiple times", arg)); - } - ty::util::NotUniqueParam::NotParam(arg) => { - err.note(&format!("`{}` is not a generic parameter", arg)); - } + tcx.def_path_str(trait_ref.def_id), + )); + match arg { + ty::util::NotUniqueParam::DuplicateParam(arg) => { + err.note(&format!("`{}` is mentioned multiple times", arg)); } - err.span_note( - item_span, - &format!( - "try using the same sequence of generic parameters as the {} definition", - self_descr, - ), - ); - err.emit(); - }, - ); - } + ty::util::NotUniqueParam::NotParam(arg) => { + err.note(&format!("`{}` is not a generic parameter", arg)); + } + } + err.span_note( + item_span, + &format!( + "try using the same sequence of generic parameters as the {} definition", + self_descr, + ), + ); + err.emit(); + }, + ); } fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool { diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs index 3cfc96ccbfd28..e45fb5fe41c02 100644 --- a/compiler/rustc_typeck/src/coherence/unsafety.rs +++ b/compiler/rustc_typeck/src/coherence/unsafety.rs @@ -6,37 +6,18 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::LocalDefId; -pub fn check(tcx: TyCtxt<'_>) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Impl) { - let item = tcx.hir().item(id); - if let hir::ItemKind::Impl(ref impl_) = item.kind { - check_unsafety_coherence( - tcx, - item, - Some(&impl_.generics), - impl_.unsafety, - impl_.polarity, - ); - } - } - } -} +pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); + let item = tcx.hir().expect_item(def_id); + let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() }; -fn check_unsafety_coherence<'tcx>( - tcx: TyCtxt<'tcx>, - item: &hir::Item<'_>, - impl_generics: Option<&hir::Generics<'_>>, - unsafety: hir::Unsafety, - polarity: hir::ImplPolarity, -) { if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) { let trait_def = tcx.trait_def(trait_ref.def_id); - let unsafe_attr = impl_generics.and_then(|generics| { - generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle") - }); - match (trait_def.unsafety, unsafe_attr, unsafety, polarity) { + let unsafe_attr = + impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); + match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) { (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => { struct_span_err!( tcx.sess, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 1f2e6ad86bd6d..6ec741269e8eb 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -59,7 +59,7 @@ struct OnlySelfBounds(bool); // Main entry point fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx }); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx }); } pub fn provide(providers: &mut Providers) { @@ -393,7 +393,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { } fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { - let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match *r { + let ty = self.tcx.fold_regions(ty, |r, _| match *r { ty::ReErased => self.tcx.lifetimes.re_static, _ => r, }); @@ -1717,8 +1717,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // provide junk type parameter defs - the only place that // cares about anything but the length is instantiation, // and we don't do that for closures. - if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { movability: gen, .. }, .. }) = - node + if let Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }), + .. + }) = node { let dummy_args = if gen.is_some() { &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..] @@ -1917,7 +1919,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. - let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r { + let fn_sig = tcx.fold_regions(fn_sig, |r, _| match *r { ty::ReErased => tcx.lifetimes.re_static, _ => r, }); @@ -2264,12 +2266,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP // compiler/tooling bugs from not handling WF predicates. } else { let span = bound_pred.bounded_ty.span; - let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::Binder::bind_with_vars( - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( - ty, - re_root_empty, - )), + ty::PredicateKind::WellFormed(ty.into()), bound_vars, ); predicates.insert((predicate.to_predicate(tcx), span)); @@ -2568,7 +2566,7 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool { 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 { - kind: rustc_hir::ExprKind::Closure { body, .. }, + kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }), .. })) => tcx.hir().body(body).generator_kind(), Some(_) => None, @@ -3200,7 +3198,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { /// Computes the set of target features used in a function for the purposes of /// inline assembly. fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> { - let mut target_features = tcx.sess.target_features.clone(); + let mut target_features = tcx.sess.unstable_target_features.clone(); if tcx.def_kind(did).has_codegen_attrs() { let attrs = tcx.codegen_fn_attrs(did); target_features.extend(&attrs.target_features); diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 7011dd6e15c21..f942a4fb53a26 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -8,7 +8,7 @@ use rustc_hir::{HirId, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -772,7 +772,7 @@ fn infer_placeholder_type<'a>( } // Typeck doesn't expect erased regions to be returned from `type_of`. - tcx.fold_regions(ty, &mut false, |r, _| match *r { + tcx.fold_regions(ty, |r, _| match *r { ty::ReErased => tcx.lifetimes.re_static, _ => r, }) diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 858cf63390a34..8428e46640671 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_middle::ty::fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::source_map::Span; use std::ops::ControlFlow; @@ -43,7 +43,7 @@ pub fn parameters_for_impl<'tcx>( /// of parameters whose values are needed in order to constrain `ty` - these /// differ, with the latter being a superset, in the presence of projections. pub fn parameters_for<'tcx>( - t: &impl TypeFoldable<'tcx>, + t: &impl TypeVisitable<'tcx>, include_nonconstraining: bool, ) -> Vec<Parameter> { let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining }; diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 67a3d4a4d020c..4cdec615d8290 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -6,18 +6,18 @@ use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] -#[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")] +#[error(typeck::field_multiply_specified_in_initializer, code = "E0062")] pub struct FieldMultiplySpecifiedInInitializer { #[primary_span] #[label] pub span: Span, - #[label = "previous-use-label"] + #[label(typeck::previous_use_label)] pub prev_span: Span, pub ident: Ident, } #[derive(SessionDiagnostic)] -#[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")] +#[error(typeck::unrecognized_atomic_operation, code = "E0092")] pub struct UnrecognizedAtomicOperation<'a> { #[primary_span] #[label] @@ -26,7 +26,7 @@ pub struct UnrecognizedAtomicOperation<'a> { } #[derive(SessionDiagnostic)] -#[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")] +#[error(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { #[primary_span] #[label] @@ -37,7 +37,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(SessionDiagnostic)] -#[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")] +#[error(typeck::unrecognized_intrinsic_function, code = "E0093")] pub struct UnrecognizedIntrinsicFunction { #[primary_span] #[label] @@ -46,19 +46,19 @@ pub struct UnrecognizedIntrinsicFunction { } #[derive(SessionDiagnostic)] -#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")] +#[error(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] pub struct LifetimesOrBoundsMismatchOnTrait { #[primary_span] #[label] pub span: Span, - #[label = "generics-label"] + #[label(typeck::generics_label)] pub generics_span: Option<Span>, pub item_kind: &'static str, pub ident: Ident, } #[derive(SessionDiagnostic)] -#[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")] +#[error(typeck::drop_impl_on_wrong_item, code = "E0120")] pub struct DropImplOnWrongItem { #[primary_span] #[label] @@ -66,18 +66,18 @@ pub struct DropImplOnWrongItem { } #[derive(SessionDiagnostic)] -#[error(code = "E0124", slug = "typeck-field-already-declared")] +#[error(typeck::field_already_declared, code = "E0124")] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] #[label] pub span: Span, - #[label = "previous-decl-label"] + #[label(typeck::previous_decl_label)] pub prev_span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")] +#[error(typeck::copy_impl_on_type_with_dtor, code = "E0184")] pub struct CopyImplOnTypeWithDtor { #[primary_span] #[label] @@ -85,14 +85,14 @@ pub struct CopyImplOnTypeWithDtor { } #[derive(SessionDiagnostic)] -#[error(code = "E0203", slug = "typeck-multiple-relaxed-default-bounds")] +#[error(typeck::multiple_relaxed_default_bounds, code = "E0203")] pub struct MultipleRelaxedDefaultBounds { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")] +#[error(typeck::copy_impl_on_non_adt, code = "E0206")] pub struct CopyImplOnNonAdt { #[primary_span] #[label] @@ -100,23 +100,23 @@ pub struct CopyImplOnNonAdt { } #[derive(SessionDiagnostic)] -#[error(code = "E0224", slug = "typeck-trait-object-declared-with-no-traits")] +#[error(typeck::trait_object_declared_with_no_traits, code = "E0224")] pub struct TraitObjectDeclaredWithNoTraits { #[primary_span] pub span: Span, - #[label = "alias-span"] + #[label(typeck::alias_span)] pub trait_alias_span: Option<Span>, } #[derive(SessionDiagnostic)] -#[error(code = "E0227", slug = "typeck-ambiguous-lifetime-bound")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0227")] pub struct AmbiguousLifetimeBound { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")] +#[error(typeck::assoc_type_binding_not_allowed, code = "E0229")] pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] @@ -124,14 +124,14 @@ pub struct AssocTypeBindingNotAllowed { } #[derive(SessionDiagnostic)] -#[error(code = "E0436", slug = "typeck-functional-record-update-on-non-struct")] +#[error(typeck::functional_record_update_on_non_struct, code = "E0436")] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")] +#[error(typeck::typeof_reserved_keyword_used, code = "E0516")] pub struct TypeofReservedKeywordUsed<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -142,25 +142,25 @@ pub struct TypeofReservedKeywordUsed<'tcx> { } #[derive(SessionDiagnostic)] -#[error(code = "E0572", slug = "typeck-return-stmt-outside-of-fn-body")] +#[error(typeck::return_stmt_outside_of_fn_body, code = "E0572")] pub struct ReturnStmtOutsideOfFnBody { #[primary_span] pub span: Span, - #[label = "encl-body-label"] + #[label(typeck::encl_body_label)] pub encl_body_span: Option<Span>, - #[label = "encl-fn-label"] + #[label(typeck::encl_fn_label)] pub encl_fn_span: Option<Span>, } #[derive(SessionDiagnostic)] -#[error(code = "E0627", slug = "typeck-yield-expr-outside-of-generator")] +#[error(typeck::yield_expr_outside_of_generator, code = "E0627")] pub struct YieldExprOutsideOfGenerator { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0639", slug = "typeck-struct-expr-non-exhaustive")] +#[error(typeck::struct_expr_non_exhaustive, code = "E0639")] pub struct StructExprNonExhaustive { #[primary_span] pub span: Span, @@ -168,26 +168,26 @@ pub struct StructExprNonExhaustive { } #[derive(SessionDiagnostic)] -#[error(code = "E0699", slug = "typeck-method-call-on-unknown-type")] +#[error(typeck::method_call_on_unknown_type, code = "E0699")] pub struct MethodCallOnUnknownType { #[primary_span] pub span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")] +#[error(typeck::value_of_associated_struct_already_specified, code = "E0719")] pub struct ValueOfAssociatedStructAlreadySpecified { #[primary_span] #[label] pub span: Span, - #[label = "previous-bound-label"] + #[label(typeck::previous_bound_label)] pub prev_span: Span, pub item_name: Ident, pub def_path: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0745", slug = "typeck-address-of-temporary-taken")] +#[error(typeck::address_of_temporary_taken, code = "E0745")] pub struct AddressOfTemporaryTaken { #[primary_span] #[label] @@ -197,7 +197,7 @@ pub struct AddressOfTemporaryTaken { #[derive(SessionSubdiagnostic)] pub enum AddReturnTypeSuggestion<'tcx> { #[suggestion( - slug = "typeck-add-return-type-add", + typeck::add_return_type_add, code = "-> {found} ", applicability = "machine-applicable" )] @@ -207,7 +207,7 @@ pub enum AddReturnTypeSuggestion<'tcx> { found: Ty<'tcx>, }, #[suggestion( - slug = "typeck-add-return-type-missing-here", + typeck::add_return_type_missing_here, code = "-> _ ", applicability = "has-placeholders" )] @@ -219,12 +219,12 @@ pub enum AddReturnTypeSuggestion<'tcx> { #[derive(SessionSubdiagnostic)] pub enum ExpectedReturnTypeLabel<'tcx> { - #[label(slug = "typeck-expected-default-return-type")] + #[label(typeck::expected_default_return_type)] Unit { #[primary_span] span: Span, }, - #[label(slug = "typeck-expected-return-type")] + #[label(typeck::expected_return_type)] Other { #[primary_span] span: Span, @@ -233,7 +233,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> { } #[derive(SessionDiagnostic)] -#[error(slug = "typeck-unconstrained-opaque-type")] +#[error(typeck::unconstrained_opaque_type)] #[note] pub struct UnconstrainedOpaqueType { #[primary_span] @@ -301,7 +301,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { } #[derive(SessionDiagnostic)] -#[error(code = "E0183", slug = "typeck-manual-implementation")] +#[error(typeck::manual_implementation, code = "E0183")] #[help] pub struct ManualImplementation { #[primary_span] @@ -311,7 +311,7 @@ pub struct ManualImplementation { } #[derive(SessionDiagnostic)] -#[error(slug = "typeck-substs-on-overridden-impl")] +#[error(typeck::substs_on_overridden_impl)] pub struct SubstsOnOverriddenImpl { #[primary_span] pub span: Span, diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 920e3d578c812..9d7420acd2662 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -2,7 +2,10 @@ //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +use std::slice::from_ref; + use hir::def::DefKind; +use hir::Expr; // Export these here so that Clippy can use them. pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; @@ -252,96 +255,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::ExprKind::Let(hir::Let { pat, init, .. }) => { - self.walk_local(init, pat, |t| t.borrow_expr(init, ty::ImmBorrow)); + self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow)) } hir::ExprKind::Match(ref discr, arms, _) => { let discr_place = return_if_err!(self.mc.cat_expr(discr)); - - // Matching should not always be considered a use of the place, hence - // discr does not necessarily need to be borrowed. - // We only want to borrow discr if the pattern contain something other - // than wildcards. - let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; - let mut needs_to_be_read = false; - for arm in arms.iter() { - return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| { - match &pat.kind { - PatKind::Binding(.., opt_sub_pat) => { - // If the opt_sub_pat is None, than the binding does not count as - // a wildcard for the purpose of borrowing discr. - if opt_sub_pat.is_none() { - needs_to_be_read = true; - } - } - PatKind::Path(qpath) => { - // A `Path` pattern is just a name like `Foo`. This is either a - // named constant or else it refers to an ADT variant - - let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); - match res { - Res::Def(DefKind::Const, _) - | Res::Def(DefKind::AssocConst, _) => { - // Named constants have to be equated with the value - // being matched, so that's a read of the value being matched. - // - // FIXME: We don't actually reads for ZSTs. - needs_to_be_read = true; - } - _ => { - // Otherwise, this is a struct/enum variant, and so it's - // only a read if we need to read the discriminant. - needs_to_be_read |= is_multivariant_adt(place.place.ty()); - } - } - } - PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => { - // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching - // against a multivariant enum or struct. In that case, we have to read - // the discriminant. Otherwise this kind of pattern doesn't actually - // read anything (we'll get invoked for the `...`, which may indeed - // perform some reads). - - let place_ty = place.place.ty(); - needs_to_be_read |= is_multivariant_adt(place_ty); - } - PatKind::Lit(_) | PatKind::Range(..) => { - // If the PatKind is a Lit or a Range then we want - // to borrow discr. - needs_to_be_read = true; - } - PatKind::Or(_) - | PatKind::Box(_) - | PatKind::Slice(..) - | PatKind::Ref(..) - | PatKind::Wild => { - // If the PatKind is Or, Box, Slice or Ref, the decision is made later - // as these patterns contains subpatterns - // If the PatKind is Wild, the decision is made based on the other patterns being - // examined - } - } - })); - } - - if needs_to_be_read { - self.borrow_expr(discr, ty::ImmBorrow); - } else { - let closure_def_id = match discr_place.place.base { - PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), - _ => None, - }; - - self.delegate.fake_read( - &discr_place, - FakeReadCause::ForMatchedPlace(closure_def_id), - discr_place.hir_id, - ); - - // We always want to walk the discriminant. We want to make sure, for instance, - // that the discriminant has been initialized. - self.walk_expr(discr); - } + self.maybe_read_scrutinee( + discr, + discr_place.clone(), + arms.iter().map(|arm| arm.pat), + ); // treatment of the discriminant is handled while walking the arms. for arm in arms { @@ -453,8 +376,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { match stmt.kind { - hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => { - self.walk_local(expr, pat, |_| {}); + hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => { + self.walk_local(expr, pat, *els, |_| {}) } hir::StmtKind::Local(_) => {} @@ -470,13 +393,114 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - fn walk_local<F>(&mut self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, mut f: F) - where + fn maybe_read_scrutinee<'t>( + &mut self, + discr: &Expr<'_>, + discr_place: PlaceWithHirId<'tcx>, + pats: impl Iterator<Item = &'t hir::Pat<'t>>, + ) { + // Matching should not always be considered a use of the place, hence + // discr does not necessarily need to be borrowed. + // We only want to borrow discr if the pattern contain something other + // than wildcards. + let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; + let mut needs_to_be_read = false; + for pat in pats { + return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { + match &pat.kind { + PatKind::Binding(.., opt_sub_pat) => { + // If the opt_sub_pat is None, than the binding does not count as + // a wildcard for the purpose of borrowing discr. + if opt_sub_pat.is_none() { + needs_to_be_read = true; + } + } + PatKind::Path(qpath) => { + // A `Path` pattern is just a name like `Foo`. This is either a + // named constant or else it refers to an ADT variant + + let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); + match res { + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { + // Named constants have to be equated with the value + // being matched, so that's a read of the value being matched. + // + // FIXME: We don't actually reads for ZSTs. + needs_to_be_read = true; + } + _ => { + // Otherwise, this is a struct/enum variant, and so it's + // only a read if we need to read the discriminant. + needs_to_be_read |= is_multivariant_adt(place.place.ty()); + } + } + } + PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => { + // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching + // against a multivariant enum or struct. In that case, we have to read + // the discriminant. Otherwise this kind of pattern doesn't actually + // read anything (we'll get invoked for the `...`, which may indeed + // perform some reads). + + let place_ty = place.place.ty(); + needs_to_be_read |= is_multivariant_adt(place_ty); + } + PatKind::Lit(_) | PatKind::Range(..) => { + // If the PatKind is a Lit or a Range then we want + // to borrow discr. + needs_to_be_read = true; + } + PatKind::Or(_) + | PatKind::Box(_) + | PatKind::Slice(..) + | PatKind::Ref(..) + | PatKind::Wild => { + // If the PatKind is Or, Box, Slice or Ref, the decision is made later + // as these patterns contains subpatterns + // If the PatKind is Wild, the decision is made based on the other patterns being + // examined + } + } + })); + } + + if needs_to_be_read { + self.borrow_expr(discr, ty::ImmBorrow); + } else { + let closure_def_id = match discr_place.place.base { + PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), + _ => None, + }; + + self.delegate.fake_read( + &discr_place, + FakeReadCause::ForMatchedPlace(closure_def_id), + discr_place.hir_id, + ); + + // We always want to walk the discriminant. We want to make sure, for instance, + // that the discriminant has been initialized. + self.walk_expr(discr); + } + } + + fn walk_local<F>( + &mut self, + expr: &hir::Expr<'_>, + pat: &hir::Pat<'_>, + els: Option<&hir::Block<'_>>, + mut f: F, + ) where F: FnMut(&mut Self), { self.walk_expr(expr); let expr_place = return_if_err!(self.mc.cat_expr(expr)); f(self); + if let Some(els) = els { + // borrowing because we need to test the descriminant + self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter()); + self.walk_block(els) + } self.walk_irrefutable_pat(&expr_place, &pat); } @@ -667,7 +691,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.kind { - debug!("walk_pat: binding place={:?} pat={:?}", place, pat,); + debug!("walk_pat: binding place={:?} pat={:?}", place, pat); if let Some(bm) = mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) { diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index 4392b9aada978..3dc728271b07a 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -72,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>( let cause = traits::ObligationCause::new( ty.span, self.hir_id, - traits::ObligationCauseCode::MiscObligation, + traits::ObligationCauseCode::WellFormed(None), ); fulfill.register_predicate_obligation( &infcx, @@ -86,7 +86,7 @@ fn diagnostic_hir_wf_check<'tcx>( let errors = fulfill.select_all_or_error(&infcx); if !errors.is_empty() { - tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors); + 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 diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs index c089d25d22216..8c26c96816d9b 100644 --- a/compiler/rustc_typeck/src/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -13,12 +13,11 @@ use min_specialization::check_min_specialization; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; -use rustc_span::Span; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_span::{Span, Symbol}; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -54,25 +53,15 @@ mod min_specialization; /// impl<'a> Trait<Foo> for Bar { type X = &'a i32; } /// // ^ 'a is unused and appears in assoc type, error /// ``` -pub fn impl_wf_check(tcx: TyCtxt<'_>) { - // We will tag this as part of the WF check -- logically, it is, - // but it's one that we must perform earlier than the rest of - // WfCheck. - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)) -} - fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let min_specialization = tcx.features().min_specialization; let module = tcx.hir_module_items(module_def_id); for id in module.items() { if matches!(tcx.def_kind(id.def_id), DefKind::Impl) { - let item = tcx.hir().item(id); - if let hir::ItemKind::Impl(ref impl_) = item.kind { - enforce_impl_params_are_constrained(tcx, item.def_id, impl_.items); - enforce_impl_items_are_distinct(tcx, impl_.items); - if min_specialization { - check_min_specialization(tcx, item.def_id.to_def_id(), item.span); - } + enforce_impl_params_are_constrained(tcx, id.def_id); + enforce_impl_items_are_distinct(tcx, id.def_id); + if min_specialization { + check_min_specialization(tcx, id.def_id); } } } @@ -82,11 +71,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_impl_wf, ..*providers }; } -fn enforce_impl_params_are_constrained( - tcx: TyCtxt<'_>, - impl_def_id: LocalDefId, - impl_item_refs: &[hir::ImplItemRef], -) { +fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id); if impl_self_ty.references_error() { @@ -114,9 +99,9 @@ fn enforce_impl_params_are_constrained( ); // Disallow unconstrained lifetimes, but only if they appear in assoc types. - let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs + let lifetimes_in_associated_types: FxHashSet<_> = tcx + .associated_item_def_ids(impl_def_id) .iter() - .map(|item_ref| item_ref.id.def_id) .flat_map(|def_id| { let item = tcx.associated_item(def_id); match item.kind { @@ -138,12 +123,7 @@ fn enforce_impl_params_are_constrained( ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - report_unused_parameter( - tcx, - tcx.def_span(param.def_id), - "type", - ¶m_ty.to_string(), - ); + report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", param_ty.name); } } ty::GenericParamDefKind::Lifetime => { @@ -155,7 +135,7 @@ fn enforce_impl_params_are_constrained( tcx, tcx.def_span(param.def_id), "lifetime", - ¶m.name.to_string(), + param.name, ); } } @@ -166,7 +146,7 @@ fn enforce_impl_params_are_constrained( tcx, tcx.def_span(param.def_id), "const", - ¶m_ct.to_string(), + param_ct.name, ); } } @@ -193,7 +173,7 @@ fn enforce_impl_params_are_constrained( // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) { +fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { let mut err = struct_span_err!( tcx.sess, span, @@ -216,33 +196,32 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) } /// Enforce that we do not have two items in an impl with the same name. -fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef]) { +fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { let mut seen_type_items = FxHashMap::default(); let mut seen_value_items = FxHashMap::default(); - for impl_item_ref in impl_item_refs { - let impl_item = tcx.hir().impl_item(impl_item_ref.id); + for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) { + let impl_item = tcx.associated_item(impl_item_ref); let seen_items = match impl_item.kind { - hir::ImplItemKind::TyAlias(_) => &mut seen_type_items, + ty::AssocKind::Type => &mut seen_type_items, _ => &mut seen_value_items, }; - match seen_items.entry(impl_item.ident.normalize_to_macros_2_0()) { + let span = tcx.def_span(impl_item_ref); + let ident = impl_item.ident(tcx); + match seen_items.entry(ident.normalize_to_macros_2_0()) { Occupied(entry) => { let mut err = struct_span_err!( tcx.sess, - impl_item.span, + span, E0201, "duplicate definitions with name `{}`:", - impl_item.ident - ); - err.span_label( - *entry.get(), - format!("previous definition of `{}` here", impl_item.ident), + ident ); - err.span_label(impl_item.span, "duplicate definition"); + err.span_label(*entry.get(), format!("previous definition of `{}` here", ident)); + err.span_label(span, "duplicate definition"); err.emit(); } Vacant(entry) => { - entry.insert(impl_item.span); + entry.insert(span); } } } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 0ecc28e6054d5..6ece955de643c 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -75,23 +75,23 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::Span; use rustc_trait_selection::traits::{self, translate_substs, wf}; -pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: DefId, span: Span) { +pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { tcx.infer_ctxt().enter(|infcx| { - check_always_applicable(&infcx, impl_def_id, node, span); + check_always_applicable(&infcx, impl_def_id, node); }); } } -fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: DefId) -> Option<Node> { +fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> { let trait_ref = tcx.impl_trait_ref(impl1_def_id)?; let trait_def = tcx.trait_def(trait_ref.def_id); - let impl2_node = trait_def.ancestors(tcx, impl1_def_id).ok()?.nth(1)?; + let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?; let always_applicable_trait = matches!(trait_def.specialization_kind, TraitSpecializationKind::AlwaysApplicable); @@ -103,15 +103,8 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: DefId) -> Option<No } /// Check that `impl1` is a sound specialization -fn check_always_applicable( - infcx: &InferCtxt<'_, '_>, - impl1_def_id: DefId, - impl2_node: Node, - span: Span, -) { - if let Some((impl1_substs, impl2_substs)) = - get_impl_substs(infcx, impl1_def_id, impl2_node, span) - { +fn check_always_applicable(infcx: &InferCtxt<'_, '_>, impl1_def_id: LocalDefId, impl2_node: Node) { + if let Some((impl1_substs, impl2_substs)) = get_impl_substs(infcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); debug!( "check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)", @@ -126,17 +119,10 @@ fn check_always_applicable( unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs) }; + let span = tcx.def_span(impl1_def_id); check_static_lifetimes(tcx, &parent_substs, span); check_duplicate_params(tcx, impl1_substs, &parent_substs, span); - - check_predicates( - infcx, - impl1_def_id.expect_local(), - impl1_substs, - impl2_node, - impl2_substs, - span, - ); + check_predicates(infcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span); } } @@ -152,20 +138,21 @@ fn check_always_applicable( /// Would return `S1 = [C]` and `S2 = [Vec<C>, C]`. fn get_impl_substs<'tcx>( infcx: &InferCtxt<'_, 'tcx>, - impl1_def_id: DefId, + impl1_def_id: LocalDefId, impl2_node: Node, - span: Span, ) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> { let tcx = infcx.tcx; let param_env = tcx.param_env(impl1_def_id); - let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); - let impl2_substs = translate_substs(infcx, param_env, impl1_def_id, impl1_substs, impl2_node); + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); + let impl2_substs = + translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); // Conservatively use an empty `ParamEnv`. let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else { + let span = tcx.def_span(impl1_def_id); tcx.sess.emit_err(SubstsOnOverriddenImpl { span }); return None; }; @@ -292,11 +279,16 @@ fn check_predicates<'tcx>( span: Span, ) { let tcx = infcx.tcx; - let impl1_predicates: Vec<_> = traits::elaborate_predicates( + let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); + let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span( tcx, - tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(), + std::iter::zip( + instantiated.predicates, + // Don't drop predicates (unsound!) because `spans` is too short + instantiated.spans.into_iter().chain(std::iter::repeat(span)), + ), ) - .map(|obligation| obligation.predicate) + .map(|obligation| (obligation.predicate, obligation.cause.span)) .collect(); let mut impl2_predicates = if impl2_node.is_from_trait() { @@ -334,7 +326,7 @@ fn check_predicates<'tcx>( // which is sound because we forbid impls like the following // // impl<D: Debug> AlwaysApplicable for D { } - let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| { + let always_applicable_traits = impl1_predicates.iter().copied().filter(|&(predicate, _)| { matches!( trait_predicate_kind(tcx, predicate), Some(TraitSpecializationKind::AlwaysApplicable) @@ -358,11 +350,11 @@ fn check_predicates<'tcx>( } } impl2_predicates.extend( - traits::elaborate_predicates(tcx, always_applicable_traits) + traits::elaborate_predicates_with_span(tcx, always_applicable_traits) .map(|obligation| obligation.predicate), ); - for predicate in impl1_predicates { + for (predicate, span) in impl1_predicates { if !impl2_predicates.contains(&predicate) { check_specialization_on(tcx, predicate, span) } @@ -397,9 +389,17 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc .emit(); } } + ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { + tcx.sess + .struct_span_err( + span, + &format!("cannot specialize on associated type `{projection_ty} == {term}`",), + ) + .emit(); + } _ => { tcx.sess - .struct_span_err(span, &format!("cannot specialize on `{:?}`", predicate)) + .struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate)) .emit(); } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index d613edf0ab0c4..706b9ee40aa99 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -65,13 +65,14 @@ This API is completely unstable and subject to change. #![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(label_break_value)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(min_specialization)] #![feature(never_type)] #![feature(once_cell)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] +#![feature(is_some_with)] #![recursion_limit = "256"] #[macro_use] @@ -223,15 +224,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { if !def_id.is_local() { return None; } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - match tcx.hir().find(hir_id) { - Some(Node::Item(hir::Item { span: item_span, .. })) => { - Some(tcx.sess.source_map().guess_head_span(*item_span)) - } - _ => { - span_bug!(tcx.def_span(def_id), "main has a non-function type"); - } - } + Some(tcx.def_span(def_id)) } fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { @@ -260,7 +253,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let mut diag = struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg); if let Some(generics_param_span) = generics_param_span { - let label = "`main` cannot have generic parameters".to_string(); + let label = "`main` cannot have generic parameters"; diag.span_label(generics_param_span, label); } diag.emit(); @@ -315,8 +308,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); if !return_ty.bound_vars().is_empty() { let msg = "`main` function return type is not allowed to have generic \ - parameters" - .to_owned(); + parameters"; struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit(); error = true; } @@ -416,7 +408,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { error = true; } if let hir::IsAsync::Async = sig.header.asyncness { - let span = tcx.sess.source_map().guess_head_span(it.span); + let span = tcx.def_span(it.def_id); struct_span_err!( tcx.sess, span, @@ -509,11 +501,21 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { } tcx.sess.track_errors(|| { - tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx)); + tcx.sess.time("impl_wf_inference", || { + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)) + }); })?; tcx.sess.track_errors(|| { - tcx.sess.time("coherence_checking", || coherence::check_coherence(tcx)); + tcx.sess.time("coherence_checking", || { + for &trait_def_id in tcx.all_local_trait_impls(()).keys() { + tcx.ensure().coherent_trait(trait_def_id); + } + + // these queries are executed for side-effects (error reporting): + tcx.ensure().crate_inherent_impls(()); + tcx.ensure().crate_inherent_impls_overlap_check(()); + }); })?; if tcx.features().rustc_attrs { @@ -523,7 +525,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { } tcx.sess.track_errors(|| { - tcx.sess.time("wf_checking", || check::check_wf_new(tcx)); + tcx.sess.time("wf_checking", || { + tcx.hir().par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) + }); })?; // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync. diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index 9acae8d79e70e..ced919f66db41 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -51,6 +51,7 @@ use rustc_middle::hir::place::*; use rustc_middle::ty::adjustment; use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index bbf31de527eb3..7534482cce9bb 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -6,7 +6,7 @@ use super::utils::*; #[derive(Debug)] pub struct ExplicitPredicatesMap<'tcx> { - map: FxHashMap<DefId, RequiredPredicates<'tcx>>, + map: FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, } impl<'tcx> ExplicitPredicatesMap<'tcx> { @@ -14,11 +14,11 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { ExplicitPredicatesMap { map: FxHashMap::default() } } - pub fn explicit_predicates_of( + pub(crate) fn explicit_predicates_of( &mut self, tcx: TyCtxt<'tcx>, def_id: DefId, - ) -> &RequiredPredicates<'tcx> { + ) -> &ty::EarlyBinder<RequiredPredicates<'tcx>> { self.map.entry(def_id).or_insert_with(|| { let predicates = if def_id.is_local() { tcx.explicit_predicates_of(def_id) @@ -63,7 +63,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { } } - required_predicates + ty::EarlyBinder(required_predicates) }) } } diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 52f9e386441a4..257a9520eeb25 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use super::explicit::ExplicitPredicatesMap; @@ -13,20 +13,19 @@ use super::utils::*; /// `global_inferred_outlives`: this is initially the empty map that /// was generated by walking the items in the crate. This will /// now be filled with inferred predicates. -pub fn infer_predicates<'tcx>( +pub(super) fn infer_predicates<'tcx>( tcx: TyCtxt<'tcx>, - explicit_map: &mut ExplicitPredicatesMap<'tcx>, -) -> FxHashMap<DefId, RequiredPredicates<'tcx>> { +) -> FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>> { debug!("infer_predicates"); - let mut predicates_added = true; + let mut explicit_map = ExplicitPredicatesMap::new(); let mut global_inferred_outlives = FxHashMap::default(); // If new predicates were added then we need to re-calculate // all crates since there could be new implied predicates. - while predicates_added { - predicates_added = false; + 'outer: loop { + let mut predicates_added = false; // Visit all the crates and infer predicates for id in tcx.hir().items() { @@ -53,9 +52,9 @@ pub fn infer_predicates<'tcx>( tcx, field_ty, field_span, - &mut global_inferred_outlives, + &global_inferred_outlives, &mut item_required_predicates, - explicit_map, + &mut explicit_map, ); } } @@ -70,12 +69,17 @@ pub fn infer_predicates<'tcx>( // we walk the crates again and re-calculate predicates for all // items. let item_predicates_len: usize = - global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len()); + global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.0.len()); if item_required_predicates.len() > item_predicates_len { predicates_added = true; - global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates); + global_inferred_outlives + .insert(item_did.to_def_id(), ty::EarlyBinder(item_required_predicates)); } } + + if !predicates_added { + break 'outer; + } } global_inferred_outlives @@ -85,7 +89,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, field_ty: Ty<'tcx>, field_span: Span, - global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>, + global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { @@ -133,11 +137,13 @@ fn insert_required_predicates_to_be_wf<'tcx>( // 'a` holds for `Foo`. debug!("Adt"); if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) { - for (unsubstituted_predicate, &span) in unsubstituted_predicates { + for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 { // `unsubstituted_predicate` is `U: 'b` in the // example above. So apply the substitution to // get `T: 'a` (or `predicate`): - let predicate = EarlyBinder(*unsubstituted_predicate).subst(tcx, substs); + let predicate = unsubstituted_predicates + .rebind(*unsubstituted_predicate) + .subst(tcx, substs); insert_outlives_predicate( tcx, predicate.0, @@ -224,7 +230,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( /// will give us `U: 'static` and `U: Foo`. The latter we /// can ignore, but we will want to process `U: 'static`, /// applying the substitution as above. -pub fn check_explicit_predicates<'tcx>( +fn check_explicit_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, substs: &[GenericArg<'tcx>], @@ -242,7 +248,7 @@ pub fn check_explicit_predicates<'tcx>( ); let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); - for (outlives_predicate, &span) in explicit_predicates { + for (outlives_predicate, &span) in &explicit_predicates.0 { debug!("outlives_predicate = {:?}", &outlives_predicate); // Careful: If we are inferring the effects of a `dyn Trait<..>` @@ -287,7 +293,7 @@ pub fn check_explicit_predicates<'tcx>( continue; } - let predicate = EarlyBinder(*outlives_predicate).subst(tcx, substs); + let predicate = explicit_predicates.rebind(*outlives_predicate).subst(tcx, substs); debug!("predicate = {:?}", &predicate); insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates); } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index dccfee19960c5..8fa65d51e3ba1 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -88,9 +88,7 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { // for the type. // Compute the inferred predicates - let mut exp_map = explicit::ExplicitPredicatesMap::new(); - - let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &mut exp_map); + let global_inferred_outlives = implicit_infer::infer_predicates(tcx); // Convert the inferred predicates into the "collected" form the // global data structure expects. @@ -100,7 +98,7 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let predicates = &*tcx.arena.alloc_from_iter(set.iter().filter_map( + let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map( |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs index 3bf697e768269..70b8bcd02208d 100644 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs @@ -1,6 +1,5 @@ use rustc_hir as hir; use rustc_middle::ty::{self, Ty}; -use rustc_span::source_map::Span; use rustc_trait_selection::infer::InferCtxt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::NoSolution; @@ -14,7 +13,6 @@ pub trait InferCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, ty: Ty<'tcx>, - span: Span, ) -> Vec<OutlivesBound<'tcx>>; } @@ -38,16 +36,14 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// Note that this may cause outlives obligations to be injected /// into the inference context with this body-id. /// - `ty`, the type that we are supposed to assume is WF. - /// - `span`, a span to use when normalizing, hopefully not important, - /// might be useful if a `bug!` occurs. - #[instrument(level = "debug", skip(self, param_env, body_id, span))] + #[instrument(level = "debug", skip(self, param_env, body_id))] fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, ty: Ty<'tcx>, - span: Span, ) -> Vec<OutlivesBound<'tcx>> { + let span = self.tcx.hir().span(body_id); let result = param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) .fully_perform(self); diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs index 14e3048cadc62..b718ca9421336 100644 --- a/compiler/rustc_typeck/src/outlives/utils.rs +++ b/compiler/rustc_typeck/src/outlives/utils.rs @@ -7,12 +7,12 @@ use std::collections::BTreeMap; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. -pub type RequiredPredicates<'tcx> = +pub(crate) type RequiredPredicates<'tcx> = BTreeMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` -pub fn insert_outlives_predicate<'tcx>( +pub(crate) fn insert_outlives_predicate<'tcx>( tcx: TyCtxt<'tcx>, kind: GenericArg<'tcx>, outlived_region: Region<'tcx>, diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs index bafc5a0b918d2..324df313ef1d8 100644 --- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs +++ b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs @@ -1,6 +1,6 @@ use crate::structured_errors::StructuredDiagnostic; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed}; -use rustc_middle::ty::{Ty, TypeFoldable}; +use rustc_middle::ty::{Ty, TypeVisitable}; use rustc_session::Session; use rustc_span::Span; diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs index afc5c1fe6cc17..bb608805488ef 100644 --- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs +++ b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs @@ -1,6 +1,6 @@ use crate::structured_errors::StructuredDiagnostic; use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed}; -use rustc_middle::ty::{Ty, TypeFoldable}; +use rustc_middle::ty::{Ty, TypeVisitable}; use rustc_session::Session; use rustc_span::Span; diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 3224864e9b1fe..469f7d1172ae6 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -126,8 +126,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn kind(&self) -> String { - if self.missing_lifetimes() { "lifetime".to_string() } else { "generic".to_string() } + fn kind(&self) -> &str { + if self.missing_lifetimes() { "lifetime" } else { "generic" } } fn num_provided_args(&self) -> usize { @@ -812,7 +812,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// Builds the `type defined here` message. fn show_definition(&self, err: &mut Diagnostic) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() { + if self.tcx.sess.source_map().is_span_accessible(def_span) { def_span.into() } else { return; @@ -836,7 +836,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .take(bound) .map(|param| { let span = self.tcx.def_span(param.def_id); - spans.push_span_label(span, String::new()); + spans.push_span_label(span, ""); param }) .map(|param| format!("`{}`", param.name)) diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index a7dcbfff207f6..d79450e1ae707 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -64,74 +64,28 @@ pub fn add_constraints_from_crate<'a, 'tcx>( let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { - constraint_cx.check_item(id); - } - - for id in crate_items.trait_items() { - if let DefKind::AssocFn = tcx.def_kind(id.def_id) { - constraint_cx.check_node_helper(id.hir_id()); - } - } - - for id in crate_items.impl_items() { - if let DefKind::AssocFn = tcx.def_kind(id.def_id) { - constraint_cx.check_node_helper(id.hir_id()); - } - } - - for id in crate_items.foreign_items() { - if let DefKind::Fn = tcx.def_kind(id.def_id) { - constraint_cx.check_node_helper(id.hir_id()); - } - } - - constraint_cx -} - -impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { - fn check_item(&mut self, id: hir::ItemId) { - let def_kind = self.tcx().def_kind(id.def_id); + for def_id in crate_items.definitions() { + let def_kind = tcx.def_kind(def_id); match def_kind { - DefKind::Struct | DefKind::Union => { - let item = self.tcx().hir().item(id); - - if let hir::ItemKind::Struct(ref struct_def, _) - | hir::ItemKind::Union(ref struct_def, _) = item.kind - { - self.check_node_helper(item.hir_id()); + DefKind::Struct | DefKind::Union | DefKind::Enum => { + constraint_cx.build_constraints_for_item(def_id); - if let hir::VariantData::Tuple(..) = *struct_def { - self.check_node_helper(struct_def.ctor_hir_id().unwrap()); + let adt = tcx.adt_def(def_id); + for variant in adt.variants() { + if let Some(ctor) = variant.ctor_def_id { + constraint_cx.build_constraints_for_item(ctor.expect_local()); } } } - DefKind::Enum => { - let item = self.tcx().hir().item(id); - - if let hir::ItemKind::Enum(ref enum_def, _) = item.kind { - self.check_node_helper(item.hir_id()); - - for variant in enum_def.variants { - if let hir::VariantData::Tuple(..) = variant.data { - self.check_node_helper(variant.data.ctor_hir_id().unwrap()); - } - } - } - } - DefKind::Fn => { - self.check_node_helper(id.hir_id()); - } + DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id), _ => {} } } - fn check_node_helper(&mut self, id: hir::HirId) { - let tcx = self.terms_cx.tcx; - let def_id = tcx.hir().local_def_id(id); - self.build_constraints_for_item(def_id); - } + constraint_cx +} +impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.terms_cx.tcx } @@ -145,8 +99,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { return; } - let id = tcx.hir().local_def_id_to_hir_id(def_id); - let inferred_start = self.terms_cx.inferred_starts[&id]; + let inferred_start = self.terms_cx.inferred_starts[&def_id]; let current_item = &CurrentItem { inferred_start }; match tcx.type_of(def_id).kind() { ty::Adt(def, _) => { @@ -372,8 +325,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } let (local, remote) = if let Some(def_id) = def_id.as_local() { - let id = self.tcx().hir().local_def_id_to_hir_id(def_id); - (Some(self.terms_cx.inferred_starts[&id]), None) + (Some(self.terms_cx.inferred_starts[&def_id]), None) } else { (None, Some(self.tcx().variances_of(def_id))) }; diff --git a/compiler/rustc_typeck/src/variance/mod.rs b/compiler/rustc_typeck/src/variance/mod.rs index e622192f2c94d..82103c5a03b6e 100644 --- a/compiler/rustc_typeck/src/variance/mod.rs +++ b/compiler/rustc_typeck/src/variance/mod.rs @@ -37,6 +37,11 @@ fn crate_variances(tcx: TyCtxt<'_>, (): ()) -> CrateVariancesMap<'_> { } fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { + // Skip items with no generics - there's nothing to infer in them. + if tcx.generics_of(item_def_id).count() == 0 { + return &[]; + } + match tcx.def_kind(item_def_id) { DefKind::Fn | DefKind::AssocFn diff --git a/compiler/rustc_typeck/src/variance/solve.rs b/compiler/rustc_typeck/src/variance/solve.rs index 1a4d88ced0e45..97aca621aa217 100644 --- a/compiler/rustc_typeck/src/variance/solve.rs +++ b/compiler/rustc_typeck/src/variance/solve.rs @@ -96,8 +96,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { self.terms_cx .inferred_starts .iter() - .map(|(&id, &InferredIndex(start))| { - let def_id = tcx.hir().local_def_id(id); + .map(|(&def_id, &InferredIndex(start))| { let generics = tcx.generics_of(def_id); let count = generics.count(); diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs index ab64befe5dc16..1f763011e0614 100644 --- a/compiler/rustc_typeck/src/variance/terms.rs +++ b/compiler/rustc_typeck/src/variance/terms.rs @@ -10,9 +10,8 @@ // a variable. use rustc_arena::DroplessArena; -use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::HirIdMap; +use rustc_hir::def_id::{LocalDefId, LocalDefIdMap}; use rustc_middle::ty::{self, TyCtxt}; use std::fmt; @@ -52,11 +51,11 @@ pub struct TermsContext<'a, 'tcx> { // For marker types, UnsafeCell, and other lang items where // variance is hardcoded, records the item-id and the hardcoded // variance. - pub lang_items: Vec<(hir::HirId, Vec<ty::Variance>)>, + pub lang_items: Vec<(LocalDefId, Vec<ty::Variance>)>, // Maps from the node id of an item to the first inferred index // used for its type & region parameters. - pub inferred_starts: HirIdMap<InferredIndex>, + pub inferred_starts: LocalDefIdMap<InferredIndex>, // Maps from an InferredIndex to the term for that variable. pub inferred_terms: Vec<VarianceTermPtr<'a>>, @@ -81,32 +80,31 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( // - https://rustc-dev-guide.rust-lang.org/variance.html let crate_items = tcx.hir_crate_items(()); - for id in crate_items.items() { - terms_cx.check_item(id); - } + for def_id in crate_items.definitions() { + debug!("add_inferreds for item {:?}", def_id); - for id in crate_items.trait_items() { - if let DefKind::AssocFn = tcx.def_kind(id.def_id) { - terms_cx.add_inferreds_for_item(id.hir_id()); - } - } + let def_kind = tcx.def_kind(def_id); - for id in crate_items.impl_items() { - if let DefKind::AssocFn = tcx.def_kind(id.def_id) { - terms_cx.add_inferreds_for_item(id.hir_id()); - } - } + match def_kind { + DefKind::Struct | DefKind::Union | DefKind::Enum => { + terms_cx.add_inferreds_for_item(def_id); - for id in crate_items.foreign_items() { - if let DefKind::Fn = tcx.def_kind(id.def_id) { - terms_cx.add_inferreds_for_item(id.hir_id()); + let adt = tcx.adt_def(def_id); + for variant in adt.variants() { + if let Some(ctor) = variant.ctor_def_id { + terms_cx.add_inferreds_for_item(ctor.expect_local()); + } + } + } + DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id), + _ => {} } } terms_cx } -fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> { +fn lang_items(tcx: TyCtxt<'_>) -> Vec<(LocalDefId, Vec<ty::Variance>)> { let lang_items = tcx.lang_items(); let all = [ (lang_items.phantom_data(), vec![ty::Covariant]), @@ -114,18 +112,16 @@ fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> { ]; all.into_iter() // iterating over (Option<DefId>, Variance) - .filter(|&(ref d, _)| d.is_some()) - .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance) .filter_map(|(d, v)| { - d.as_local().map(|d| tcx.hir().local_def_id_to_hir_id(d)).map(|n| (n, v)) - }) // (HirId, Variance) + let def_id = d?.as_local()?; // LocalDefId + Some((def_id, v)) + }) .collect() } impl<'a, 'tcx> TermsContext<'a, 'tcx> { - fn add_inferreds_for_item(&mut self, id: hir::HirId) { + fn add_inferreds_for_item(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let def_id = tcx.hir().local_def_id(id); let count = tcx.generics_of(def_id).count(); if count == 0 { @@ -134,7 +130,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { // Record the start of this item's inferreds. let start = self.inferred_terms.len(); - let newly_added = self.inferred_starts.insert(id, InferredIndex(start)).is_none(); + let newly_added = self.inferred_starts.insert(def_id, InferredIndex(start)).is_none(); assert!(newly_added); // N.B., in the code below for writing the results back into the @@ -146,42 +142,4 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { (start..(start + count)).map(|i| &*arena.alloc(InferredTerm(InferredIndex(i)))), ); } - - fn check_item(&mut self, id: hir::ItemId) { - debug!("add_inferreds for item {}", self.tcx.hir().node_to_string(id.hir_id())); - - let def_kind = self.tcx.def_kind(id.def_id); - match def_kind { - DefKind::Struct | DefKind::Union => { - let item = self.tcx.hir().item(id); - - if let hir::ItemKind::Struct(ref struct_def, _) - | hir::ItemKind::Union(ref struct_def, _) = item.kind - { - self.add_inferreds_for_item(item.hir_id()); - - if let hir::VariantData::Tuple(..) = *struct_def { - self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap()); - } - } - } - DefKind::Enum => { - let item = self.tcx.hir().item(id); - - if let hir::ItemKind::Enum(ref enum_def, _) = item.kind { - self.add_inferreds_for_item(item.hir_id()); - - for variant in enum_def.variants { - if let hir::VariantData::Tuple(..) = variant.data { - self.add_inferreds_for_item(variant.data.ctor_hir_id().unwrap()); - } - } - } - } - DefKind::Fn => { - self.add_inferreds_for_item(id.hir_id()); - } - _ => {} - } - } } diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 7a79fb77dea55..904a53bb4acc7 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -60,7 +60,7 @@ pub trait ToOwned { /// Uses borrowed data to replace owned data, usually by cloning. /// - /// This is borrow-generalized version of `Clone::clone_from`. + /// This is borrow-generalized version of [`Clone::clone_from`]. /// /// # Examples /// diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index cc395759b2078..c1ceeb0deb837 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -206,7 +206,7 @@ impl<T> Box<T> { /// ``` /// let five = Box::new(5); /// ``` - #[cfg(all(not(no_global_oom_handling), not(bootstrap)))] + #[cfg(all(not(no_global_oom_handling)))] #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] @@ -215,23 +215,6 @@ impl<T> Box<T> { Box::new(x) } - /// Allocates memory on the heap and then places `x` into it. - /// - /// This doesn't actually allocate if `T` is zero-sized. - /// - /// # Examples - /// - /// ``` - /// let five = Box::new(5); - /// ``` - #[cfg(all(not(no_global_oom_handling), bootstrap))] - #[inline(always)] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn new(x: T) -> Self { - box x - } - /// Constructs a new box with uninitialized contents. /// /// # Examples @@ -296,7 +279,7 @@ impl<T> Box<T> { #[must_use] #[inline(always)] pub fn pin(x: T) -> Pin<Box<T>> { - (#[cfg_attr(not(bootstrap), rustc_box)] + (#[rustc_box] Box::new(x)) .into() } @@ -966,6 +949,7 @@ impl<T: ?Sized> Box<T> { /// [`Layout`]: crate::Layout #[stable(feature = "box_raw", since = "1.4.0")] #[inline] + #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"] pub unsafe fn from_raw(raw: *mut T) -> Self { unsafe { Self::from_raw_in(raw, Global) } } @@ -1255,7 +1239,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> { impl<T: Default> Default for Box<T> { /// Creates a `Box<T>`, with the `Default` value for T. fn default() -> Self { - #[cfg_attr(not(bootstrap), rustc_box)] + #[rustc_box] Box::new(T::default()) } } @@ -1628,7 +1612,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> { /// println!("{boxed:?}"); /// ``` fn from(array: [T; N]) -> Box<[T]> { - #[cfg_attr(not(bootstrap), rustc_box)] + #[rustc_box] Box::new(array) } } diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 807c035fdbd0d..649ccfcaa9ed8 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -3,7 +3,9 @@ // by matthieu-m use crate::alloc::{self, Layout, LayoutError}; use core::fmt::{self, Debug, Display, Formatter}; -use core::marker::{PhantomData, Unsize}; +use core::marker::PhantomData; +#[cfg(not(no_global_oom_handling))] +use core::marker::Unsize; use core::mem; use core::ops::{Deref, DerefMut}; use core::ptr::Pointee; @@ -29,10 +31,20 @@ use core::ptr::{self, NonNull}; /// ``` #[unstable(feature = "thin_box", issue = "92791")] pub struct ThinBox<T: ?Sized> { - ptr: WithHeader<<T as Pointee>::Metadata>, + // This is essentially `WithHeader<<T as Pointee>::Metadata>`, + // but that would be invariant in `T`, and we want covariance. + ptr: WithOpaqueHeader, _marker: PhantomData<T>, } +/// `ThinBox<T>` is `Send` if `T` is `Send` because the data is owned. +#[unstable(feature = "thin_box", issue = "92791")] +unsafe impl<T: ?Sized + Send> Send for ThinBox<T> {} + +/// `ThinBox<T>` is `Sync` if `T` is `Sync` because the data is owned. +#[unstable(feature = "thin_box", issue = "92791")] +unsafe impl<T: ?Sized + Sync> Sync for ThinBox<T> {} + #[unstable(feature = "thin_box", issue = "92791")] impl<T> ThinBox<T> { /// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on @@ -49,7 +61,7 @@ impl<T> ThinBox<T> { #[cfg(not(no_global_oom_handling))] pub fn new(value: T) -> Self { let meta = ptr::metadata(&value); - let ptr = WithHeader::new(meta, value); + let ptr = WithOpaqueHeader::new(meta, value); ThinBox { ptr, _marker: PhantomData } } } @@ -73,7 +85,7 @@ impl<Dyn: ?Sized> ThinBox<Dyn> { T: Unsize<Dyn>, { let meta = ptr::metadata(&value as &Dyn); - let ptr = WithHeader::new(meta, value); + let ptr = WithOpaqueHeader::new(meta, value); ThinBox { ptr, _marker: PhantomData } } } @@ -120,7 +132,7 @@ impl<T: ?Sized> Drop for ThinBox<T> { unsafe { let value = self.deref_mut(); let value = value as *mut T; - self.ptr.drop::<T>(value); + self.with_header().drop::<T>(value); } } } @@ -130,11 +142,16 @@ impl<T: ?Sized> ThinBox<T> { fn meta(&self) -> <T as Pointee>::Metadata { // Safety: // - NonNull and valid. - unsafe { *self.ptr.header() } + unsafe { *self.with_header().header() } } fn data(&self) -> *mut u8 { - self.ptr.value() + self.with_header().value() + } + + fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> { + // SAFETY: both types are transparent to `NonNull<u8>` + unsafe { &*((&self.ptr) as *const WithOpaqueHeader as *const WithHeader<_>) } } } @@ -143,8 +160,22 @@ impl<T: ?Sized> ThinBox<T> { /// metadata (`H`) are ZSTs. /// 2. A pointer to a valid `T` that has a header `H` directly before the /// pointed-to location. +#[repr(transparent)] struct WithHeader<H>(NonNull<u8>, PhantomData<H>); +/// An opaque representation of `WithHeader<H>` to avoid the +/// projection invariance of `<T as Pointee>::Metadata`. +#[repr(transparent)] +struct WithOpaqueHeader(NonNull<u8>); + +impl WithOpaqueHeader { + #[cfg(not(no_global_oom_handling))] + fn new<H, T>(header: H, value: T) -> Self { + let ptr = WithHeader::new(header, value); + Self(ptr.0) + } +} + impl<H> WithHeader<H> { #[cfg(not(no_global_oom_handling))] fn new<T>(header: H, value: T) -> WithHeader<H> { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index cde4219be84c2..ae61b1f1e8ed5 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -108,7 +108,7 @@ use crate::sync::Arc; /// and other memory errors. #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")] -#[unstable(feature = "alloc_c_string", issue = "94079")] +#[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct CString { // Invariant 1: the slice ends with a zero byte and has a length of at least one. // Invariant 2: the slice contains only one zero byte. @@ -132,7 +132,7 @@ pub struct CString { /// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err(); /// ``` #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "alloc_c_string", issue = "94079")] +#[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct NulError(usize, Vec<u8>); #[derive(Clone, PartialEq, Eq, Debug)] @@ -157,7 +157,7 @@ enum FromBytesWithNulErrorKind { /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err(); /// ``` #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "alloc_c_string", issue = "94079")] +#[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct FromVecWithNulError { error_kind: FromBytesWithNulErrorKind, bytes: Vec<u8>, @@ -223,7 +223,7 @@ impl FromVecWithNulError { /// This `struct` is created by [`CString::into_string()`]. See /// its documentation for more. #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "alloc_c_string", issue = "94079")] +#[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct IntoStringError { inner: CString, error: Utf8Error, diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs index fec2bec566a8b..e8530fbc1f08f 100644 --- a/library/alloc/src/ffi/mod.rs +++ b/library/alloc/src/ffi/mod.rs @@ -78,11 +78,11 @@ //! [`String`]: crate::string::String //! [`CStr`]: core::ffi::CStr -#![unstable(feature = "alloc_ffi", issue = "94079")] +#![stable(feature = "alloc_ffi", since = "1.64.0")] -#[unstable(feature = "alloc_c_string", issue = "94079")] +#[stable(feature = "alloc_c_string", since = "1.64.0")] pub use self::c_str::FromVecWithNulError; -#[unstable(feature = "alloc_c_string", issue = "94079")] +#[stable(feature = "alloc_c_string", since = "1.64.0")] pub use self::c_str::{CString, IntoStringError, NulError}; mod c_str; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index c08caa7b93ed2..315469387e5ae 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -86,7 +86,6 @@ #![allow(explicit_outlives_requirements)] // // Library features: -#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] @@ -106,9 +105,7 @@ #![feature(const_maybe_uninit_write)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_refs_to_cell)] -#![feature(core_c_str)] #![feature(core_intrinsics)] -#![feature(core_ffi_c)] #![feature(const_eval_select)] #![feature(const_pin)] #![feature(cstr_from_bytes_until_nul)] @@ -125,6 +122,7 @@ #![cfg_attr(test, feature(new_uninit))] #![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] +#![feature(pointer_byte_offsets)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] @@ -149,7 +147,6 @@ #![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(associated_type_bounds)] -#![cfg_attr(bootstrap, feature(box_syntax))] #![feature(cfg_sanitize)] #![feature(const_deref)] #![feature(const_mut_refs)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 37898b6655faa..88eb6aa7a83c1 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -34,7 +34,7 @@ /// be mindful of side effects. /// /// [`Vec`]: crate::vec::Vec -#[cfg(all(not(no_global_oom_handling), not(test), not(bootstrap)))] +#[cfg(all(not(no_global_oom_handling), not(test)))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_macro"] @@ -54,24 +54,6 @@ macro_rules! vec { ); } -/// Creates a `Vec` containing the arguments (bootstrap version). -#[cfg(all(not(no_global_oom_handling), not(test), bootstrap))] -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "vec_macro"] -#[allow_internal_unstable(box_syntax, liballoc_internals)] -macro_rules! vec { - () => ( - $crate::__rust_force_expr!($crate::vec::Vec::new()) - ); - ($elem:expr; $n:expr) => ( - $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n)) - ); - ($($x:expr),+ $(,)?) => ( - $crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+])) - ); -} - // HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is // required for this macro definition, is not available. Instead use the // `slice::into_vec` function which is only available with cfg(test) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 4be5f6cf9ca51..b0f4529abdfa5 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -421,6 +421,7 @@ impl<T, A: Allocator> RawVec<T, A> { Ok(()) } + #[cfg(not(no_global_oom_handling))] fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity"); diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a248cd458df81..b89b03683baef 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -907,8 +907,7 @@ impl<T: ?Sized> Rc<T> { let offset = unsafe { data_offset(ptr) }; // Reverse the offset to find the original RcBox. - let rc_ptr = - unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut RcBox<T>) }; + let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcBox<T> }; unsafe { Self::from_ptr(rc_ptr) } } @@ -2331,7 +2330,7 @@ impl<T: ?Sized> Weak<T> { let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut RcBox<T>) } + unsafe { ptr.byte_sub(offset) as *mut RcBox<T> } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. @@ -2684,7 +2683,7 @@ impl<T: ?Sized> Unpin for Rc<T> {} /// /// The pointer must point to (and have valid metadata for) a previously /// valid instance of T, but the T is allowed to be dropped. -unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { +unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize { // Align the unsized value to the end of the RcBox. // Because RcBox is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, @@ -2695,7 +2694,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { } #[inline] -fn data_offset_align(align: usize) -> isize { +fn data_offset_align(align: usize) -> usize { let layout = Layout::new::<RcBox<()>>(); - (layout.size() + layout.padding_needed_for(align)) as isize + layout.size() + layout.padding_needed_for(align) } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 4a9cecd9b4e1a..63d4d94529008 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -836,14 +836,14 @@ impl<T: Clone, V: Borrow<[T]>> Join<&[T]> for [V] { //////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Borrow<[T]> for Vec<T> { +impl<T, A: Allocator> Borrow<[T]> for Vec<T, A> { fn borrow(&self) -> &[T] { &self[..] } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> BorrowMut<[T]> for Vec<T> { +impl<T, A: Allocator> BorrowMut<[T]> for Vec<T, A> { fn borrow_mut(&mut self) -> &mut [T] { &mut self[..] } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 8883880726594..b1513e5e0f31c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -46,9 +46,9 @@ use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; +use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] -use core::iter::FromIterator; -use core::iter::{from_fn, FusedIterator}; +use core::iter::{from_fn, FromIterator}; #[cfg(not(no_global_oom_handling))] use core::ops::Add; #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 24e849aab4cce..4c03cc3ed158a 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -908,8 +908,7 @@ impl<T: ?Sized> Arc<T> { let offset = data_offset(ptr); // Reverse the offset to find the original ArcInner. - let arc_ptr = - (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut ArcInner<T>); + let arc_ptr = ptr.byte_sub(offset) as *mut ArcInner<T>; Self::from_ptr(arc_ptr) } @@ -1942,7 +1941,7 @@ impl<T: ?Sized> Weak<T> { let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. // SAFETY: the pointer originated from a Weak, so this offset is safe. - unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut ArcInner<T>) } + unsafe { ptr.byte_sub(offset) as *mut ArcInner<T> } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. @@ -2749,7 +2748,7 @@ impl<T: ?Sized> Unpin for Arc<T> {} /// /// The pointer must point to (and have valid metadata for) a previously /// valid instance of T, but the T is allowed to be dropped. -unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { +unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize { // Align the unsized value to the end of the ArcInner. // Because RcBox is repr(C), it will always be the last field in memory. // SAFETY: since the only unsized types possible are slices, trait objects, @@ -2760,7 +2759,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { } #[inline] -fn data_offset_align(align: usize) -> isize { +fn data_offset_align(align: usize) -> usize { let layout = Layout::new::<ArcInner<()>>(); - (layout.size() + layout.padding_needed_for(align)) as isize + layout.size() + layout.padding_needed_for(align) } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 9b84a1d9b4b64..28979457b7fd3 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -9,6 +9,7 @@ use core::iter::{ }; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; +#[cfg(not(no_global_oom_handling))] use core::ops::Deref; use core::ptr::{self, NonNull}; use core::slice::{self}; @@ -123,6 +124,7 @@ impl<T, A: Allocator> IntoIter<T, A> { } /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed. + #[cfg(not(no_global_oom_handling))] pub(crate) fn forget_remaining_elements(&mut self) { self.ptr = self.end; } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e25f98d8aa695..fa9f2131c0c1d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1379,9 +1379,6 @@ impl<T, A: Allocator> Vec<T, A> { } let len = self.len(); - if index > len { - assert_failed(index, len); - } // space for the new element if len == self.buf.capacity() { @@ -1393,9 +1390,15 @@ impl<T, A: Allocator> Vec<T, A> { // The spot to put the new value { let p = self.as_mut_ptr().add(index); - // Shift everything over to make space. (Duplicating the - // `index`th element into two consecutive places.) - ptr::copy(p, p.offset(1), len - index); + if index < len { + // Shift everything over to make space. (Duplicating the + // `index`th element into two consecutive places.) + ptr::copy(p, p.offset(1), len - index); + } else if index == len { + // No elements need shifting. + } else { + assert_failed(index, len); + } // Write it in, overwriting the first copy of the `index`th // element. ptr::write(p, element); @@ -3017,7 +3020,7 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> { #[cfg(not(test))] fn from(s: [T; N]) -> Vec<T> { <[T]>::into_vec( - #[cfg_attr(not(bootstrap), rustc_box)] + #[rustc_box] Box::new(s), ) } diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs index 67e12c612dbb1..5ee6db43fda24 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloc/tests/fmt.rs @@ -207,7 +207,7 @@ fn test_format_macro_interface() { { let val = usize::MAX; let exp = format!("{val:#x}"); - t!(format!("{:p}", val as *const isize), exp); + t!(format!("{:p}", std::ptr::invalid::<isize>(val)), exp); } // Escaping diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 367cdcdcc061c..c29e7b9c81efb 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -11,8 +11,6 @@ #![feature(const_nonnull_slice_from_raw_parts)] #![feature(const_ptr_write)] #![feature(const_try)] -#![feature(core_c_str)] -#![feature(core_ffi_c)] #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index b6836fdc88ee8..99d1296a4c925 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -693,12 +693,6 @@ fn test_try_reserve() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - // On 16/32-bit, we check that allocations don't exceed isize::MAX, - // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. - // Any platform that succeeds for these requests is technically broken with - // ptr::offset because LLVM is the worst. - let guards_against_isize = usize::BITS < 64; - { // Note: basic stuff is checked by test_reserve let mut empty_string: String = String::new(); @@ -712,35 +706,19 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX + 1 is an OOM - assert_matches!( - empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - // Check usize::MAX is an OOM - assert_matches!( - empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -753,19 +731,13 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -785,8 +757,6 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = usize::BITS < 64; - { let mut empty_string: String = String::new(); @@ -799,31 +769,17 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - assert_matches!( - empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - assert_matches!( - empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -839,19 +795,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs index 70d1db8b45766..368aa564f9436 100644 --- a/library/alloc/tests/thin_box.rs +++ b/library/alloc/tests/thin_box.rs @@ -26,6 +26,13 @@ fn want_thin() { assert!(is_thin::<i32>()); } +#[allow(dead_code)] +fn assert_covariance() { + fn thin_box<'new>(b: ThinBox<[&'static str]>) -> ThinBox<[&'new str]> { + b + } +} + #[track_caller] fn verify_aligned<T>(ptr: *const T) { // Use `black_box` to attempt to obscure the fact that we're calling this diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 5520f6ebf1904..699567be5a004 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1517,12 +1517,6 @@ fn test_try_reserve() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - // On 16/32-bit, we check that allocations don't exceed isize::MAX, - // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. - // Any platform that succeeds for these requests is technically broken with - // ptr::offset because LLVM is the worst. - let guards_against_isize = usize::BITS < 64; - { // Note: basic stuff is checked by test_reserve let mut empty_bytes: Vec<u8> = Vec::new(); @@ -1536,35 +1530,19 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX + 1 is an OOM - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - // Check usize::MAX is an OOM - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1577,19 +1555,13 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -1610,19 +1582,13 @@ fn test_try_reserve() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should fail in the mul-by-size assert_matches!( ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), @@ -1642,8 +1608,6 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::<usize>() < 8; - { let mut empty_bytes: Vec<u8> = Vec::new(); @@ -1656,31 +1620,17 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(AllocError { .. }), - "usize::MAX should trigger an OOM!" - ); - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1696,19 +1646,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), @@ -1729,19 +1673,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 89cc7f905be2c..019d73c0b16bb 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,7 +2,6 @@ use std::assert_matches::assert_matches; use std::collections::TryReserveErrorKind::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; -use std::mem::size_of; use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -1161,12 +1160,6 @@ fn test_try_reserve() { const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; const MAX_USIZE: usize = usize::MAX; - // On 16/32-bit, we check that allocations don't exceed isize::MAX, - // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. - // Any platform that succeeds for these requests is technically broken with - // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::<usize>() < 8; - { // Note: basic stuff is checked by test_reserve let mut empty_bytes: VecDeque<u8> = VecDeque::new(); @@ -1180,31 +1173,19 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX is an OOM - // VecDeque starts with capacity 7, always adds 1 to the capacity - // and also rounds the number to next power of 2 so this is the - // furthest we can go without triggering CapacityOverflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1217,19 +1198,13 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -1250,19 +1225,13 @@ fn test_try_reserve() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + // Should fail in the mul-by-size assert_matches!( ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), @@ -1282,8 +1251,6 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::<usize>() < 8; - { let mut empty_bytes: VecDeque<u8> = VecDeque::new(); @@ -1296,29 +1263,17 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); - } else { - // Check isize::MAX is an OOM - // VecDeque starts with capacity 7, always adds 1 to the capacity - // and also rounds the number to next power of 2 so this is the - // furthest we can go without triggering CapacityOverflow - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); } { @@ -1334,19 +1289,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), @@ -1367,19 +1316,13 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - if guards_against_isize { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - } else { - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(AllocError { .. }), - "isize::MAX + 1 should trigger an OOM!" - ); - } + + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + assert_matches!( ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 2f378836cbbb3..59ebe5fbe0227 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -1,3 +1,9 @@ +// Seemingly inconsequential code changes to this file can lead to measurable +// performance impact on compilation times, due at least in part to the fact +// that the layout code gets called from many instantiations of the various +// collections, resulting in having to optimize down excess IR multiple times. +// Your performance intuition is useless. Run perf. + use crate::cmp; use crate::fmt; use crate::mem::{self, ValidAlign}; @@ -52,8 +58,8 @@ impl Layout { /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e., the rounded value must be less than - /// or equal to `usize::MAX`). + /// must not overflow isize (i.e., the rounded value must be + /// less than or equal to `isize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] @@ -62,6 +68,13 @@ impl Layout { return Err(LayoutError); } + // SAFETY: just checked that align is a power of two. + Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) }) + } + + /// Internal helper constructor to skip revalidating alignment validity. + #[inline] + const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> { // (power-of-two implies align != 0.) // Rounded up size is: @@ -76,13 +89,12 @@ impl Layout { // // Above implies that checking for summation overflow is both // necessary and sufficient. - if size > usize::MAX - (align - 1) { + if size > isize::MAX as usize - (align.as_nonzero().get() - 1) { return Err(LayoutError); } - // SAFETY: the conditions for `from_size_align_unchecked` have been - // checked above. - unsafe { Ok(Layout::from_size_align_unchecked(size, align)) } + // SAFETY: Layout::size invariants checked above. + Ok(Layout { size, align }) } /// Creates a layout, bypassing all checks. @@ -96,8 +108,8 @@ impl Layout { #[must_use] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - // SAFETY: the caller must ensure that `align` is a power of two. - Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } } + // SAFETY: the caller is required to uphold the preconditions. + unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } } } /// The minimum size in bytes for a memory block of this layout. @@ -126,10 +138,9 @@ impl Layout { #[inline] pub const fn new<T>() -> Self { let (size, align) = size_align::<T>(); - // SAFETY: the align is guaranteed by Rust to be a power of two and - // the size+align combo is guaranteed to fit in our address space. As a - // result use the unchecked constructor here to avoid inserting code - // that panics if it isn't optimized well enough. + // SAFETY: if the type is instantiated, rustc already ensures that its + // layout is valid. Use the unchecked constructor to avoid inserting a + // panicking codepath that needs to be optimized out. unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -141,7 +152,6 @@ impl Layout { #[inline] pub fn for_value<T: ?Sized>(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -176,7 +186,6 @@ impl Layout { pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) }; - debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -276,12 +285,11 @@ impl Layout { let pad = self.padding_needed_for(self.align()); // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow (i.e., the rounded value must be less than - // > `usize::MAX`) + // > must not overflow isize (i.e., the rounded value must be + // > less than or equal to `isize::MAX`) let new_size = self.size() + pad; - // SAFETY: self.align is already known to be valid and new_size has been - // padded already. + // SAFETY: padded size is guaranteed to not exceed `isize::MAX`. unsafe { Layout::from_size_align_unchecked(new_size, self.align()) } } @@ -298,14 +306,13 @@ impl Layout { pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow (i.e., the rounded value must be less than - // > `usize::MAX`) + // > must not overflow isize (i.e., the rounded value must be + // > less than or equal to `isize::MAX`) let padded_size = self.size() + self.padding_needed_for(self.align()); let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; - // SAFETY: self.align is already known to be valid and alloc_size has been - // padded already. - unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) } + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(alloc_size, self.align).map(|layout| (layout, padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -356,13 +363,14 @@ impl Layout { #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { - let new_align = cmp::max(self.align(), next.align()); + let new_align = cmp::max(self.align, next.align); let pad = self.padding_needed_for(next.align()); let offset = self.size().checked_add(pad).ok_or(LayoutError)?; let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?; - let layout = Layout::from_size_align(new_size, new_align)?; + // The safe constructor is called here to enforce the isize size limit. + let layout = Layout::from_size_valid_align(new_size, new_align)?; Ok((layout, offset)) } @@ -382,7 +390,8 @@ impl Layout { #[inline] pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> { let size = self.size().checked_mul(n).ok_or(LayoutError)?; - Layout::from_size_align(size, self.align()) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(size, self.align) } /// Creates a layout describing the record for `self` followed by @@ -395,7 +404,8 @@ impl Layout { #[inline] pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> { let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?; - Layout::from_size_align(new_size, self.align()) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(new_size, self.align) } /// Creates a layout describing the record for a `[T; n]`. @@ -405,16 +415,8 @@ impl Layout { #[inline] pub fn array<T>(n: usize) -> Result<Self, LayoutError> { let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?; - - // SAFETY: - // - Size: `array_size` cannot be too big because `size_of::<T>()` must - // be a multiple of `align_of::<T>()`. Therefore, `array_size` - // rounded up to the nearest multiple of `align_of::<T>()` is just - // `array_size`. And `array_size` cannot be too big because it was - // just checked by the `checked_mul()`. - // - Alignment: `align_of::<T>()` will always give an acceptable - // (non-zero, power of two) alignment. - Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) }) + // The safe constructor is called here to enforce the isize size limit. + Layout::from_size_valid_align(array_size, ValidAlign::of::<T>()) } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 2ea4458bf6427..c9823a136bc42 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -780,8 +780,8 @@ where } /// Pulls `N` items from `iter` and returns them as an array. If the iterator -/// yields fewer than `N` items, `None` is returned and all already yielded -/// items are dropped. +/// yields fewer than `N` items, `Err` is returned containing an iterator over +/// the already yielded items. /// /// Since the iterator is passed as a mutable reference and this function calls /// `next` at most `N` times, the iterator can still be used afterwards to @@ -789,7 +789,10 @@ where /// /// If `iter.next()` panicks, all items already yielded by the iterator are /// dropped. -fn try_collect_into_array<I, T, R, const N: usize>(iter: &mut I) -> Option<R::TryType> +#[inline] +fn try_collect_into_array<I, T, R, const N: usize>( + iter: &mut I, +) -> Result<R::TryType, IntoIter<T, N>> where I: Iterator, I::Item: Try<Output = T, Residual = R>, @@ -797,7 +800,7 @@ where { if N == 0 { // SAFETY: An empty array is always inhabited and has no validity invariants. - return unsafe { Some(Try::from_output(mem::zeroed())) }; + return Ok(Try::from_output(unsafe { mem::zeroed() })); } struct Guard<'a, T, const N: usize> { @@ -821,35 +824,49 @@ where let mut array = MaybeUninit::uninit_array::<N>(); let mut guard = Guard { array_mut: &mut array, initialized: 0 }; - while let Some(item_rslt) = iter.next() { - let item = match item_rslt.branch() { - ControlFlow::Break(r) => { - return Some(FromResidual::from_residual(r)); + for _ in 0..N { + match iter.next() { + Some(item_rslt) => { + let item = match item_rslt.branch() { + ControlFlow::Break(r) => { + return Ok(FromResidual::from_residual(r)); + } + ControlFlow::Continue(elem) => elem, + }; + + // SAFETY: `guard.initialized` starts at 0, is increased by one in the + // loop and the loop is aborted once it reaches N (which is + // `array.len()`). + unsafe { + guard.array_mut.get_unchecked_mut(guard.initialized).write(item); + } + guard.initialized += 1; + } + None => { + let alive = 0..guard.initialized; + mem::forget(guard); + // SAFETY: `array` was initialized with exactly `initialized` + // number of elements. + return Err(unsafe { IntoIter::new_unchecked(array, alive) }); } - ControlFlow::Continue(elem) => elem, - }; - - // SAFETY: `guard.initialized` starts at 0, is increased by one in the - // loop and the loop is aborted once it reaches N (which is - // `array.len()`). - unsafe { - guard.array_mut.get_unchecked_mut(guard.initialized).write(item); - } - guard.initialized += 1; - - // Check if the whole array was initialized. - if guard.initialized == N { - mem::forget(guard); - - // SAFETY: the condition above asserts that all elements are - // initialized. - let out = unsafe { MaybeUninit::array_assume_init(array) }; - return Some(Try::from_output(out)); } } - // This is only reached if the iterator is exhausted before - // `guard.initialized` reaches `N`. Also note that `guard` is dropped here, - // dropping all already initialized elements. - None + mem::forget(guard); + // SAFETY: All elements of the array were populated in the loop above. + let output = unsafe { MaybeUninit::array_assume_init(array) }; + Ok(Try::from_output(output)) +} + +/// Returns the next chunk of `N` items from the iterator or errors with an +/// iterator over the remainder. Used for `Iterator::next_chunk`. +#[inline] +pub(crate) fn iter_next_chunk<I, const N: usize>( + iter: &mut I, +) -> Result<[I::Item; N], IntoIter<I::Item, N>> +where + I: Iterator, +{ + let mut map = iter.map(NeverShortCircuit); + try_collect_into_array(&mut map).map(|NeverShortCircuit(arr)| arr) } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 63c83ddb6f7cf..8a37fadc56f4c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1856,7 +1856,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> { #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] -#[repr(no_niche)] // rust-lang/rust#68303. pub struct UnsafeCell<T: ?Sized> { value: T, } diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 778f06aeb63e6..7c5f82f5ea49d 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -93,7 +93,7 @@ impl const From<char> for u128 { /// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing /// if the code point is greater than U+00FF. /// -/// See [`impl From<u8> for char`](char#impl-From<u8>) for details on the encoding. +/// See [`impl From<u8> for char`](char#impl-From<u8>-for-char) for details on the encoding. #[stable(feature = "u8_from_char", since = "1.59.0")] impl TryFrom<char> for u8 { type Error = TryFromCharError; @@ -229,7 +229,7 @@ impl TryFrom<u32> for char { /// The error type returned when a conversion from [`prim@u32`] to [`prim@char`] fails. /// -/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>) method. +/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>-for-char) method. /// See its documentation for more. #[stable(feature = "try_from", since = "1.34.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index fd5624812f554..06dca7e59a2a6 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -106,7 +106,7 @@ use crate::marker::Destruct; #[lang = "clone"] #[rustc_diagnostic_item = "Clone"] #[rustc_trivial_field_reads] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] pub trait Clone: Sized { /// Returns a copy of the value. /// @@ -129,7 +129,6 @@ pub trait Clone: Sized { /// allocations. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(bootstrap, default_method_body_is_const)] fn clone_from(&mut self, source: &Self) where Self: ~const Destruct, diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 064675ee7cf24..1d3466696ed04 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -214,7 +214,7 @@ use self::Ordering::*; append_const_msg, ) )] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] #[rustc_diagnostic_item = "PartialEq"] pub trait PartialEq<Rhs: ?Sized = Self> { /// This method tests for `self` and `other` values to be equal, and is used @@ -227,7 +227,6 @@ pub trait PartialEq<Rhs: ?Sized = Self> { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(bootstrap, default_method_body_is_const)] fn ne(&self, other: &Rhs) -> bool { !self.eq(other) } @@ -1054,7 +1053,7 @@ impl PartialOrd for Ordering { append_const_msg, ) )] -#[cfg_attr(not(bootstrap), const_trait)] +#[const_trait] #[rustc_diagnostic_item = "PartialOrd"] pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { /// This method returns an ordering between `self` and `other` values if one exists. @@ -1098,7 +1097,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(bootstrap, default_method_body_is_const)] fn lt(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Less)) } @@ -1118,7 +1116,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(bootstrap, default_method_body_is_const)] fn le(&self, other: &Rhs) -> bool { // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`. // FIXME: The root cause was fixed upstream in LLVM with: @@ -1141,7 +1138,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(bootstrap, default_method_body_is_const)] fn gt(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Greater)) } @@ -1161,7 +1157,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(bootstrap, default_method_body_is_const)] fn ge(&self, other: &Rhs) -> bool { matches!(self.partial_cmp(other), Some(Greater | Equal)) } diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 10bf95abd3959..ee9baf811e29c 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -76,7 +76,7 @@ use crate::str; /// [str]: prim@str "str" #[derive(Hash)] #[cfg_attr(not(test), rustc_diagnostic_item = "CStr")] -#[unstable(feature = "core_c_str", issue = "94079")] +#[stable(feature = "core_c_str", since = "1.64.0")] #[rustc_has_incoherent_inherent_impls] // FIXME: // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies @@ -108,7 +108,7 @@ pub struct CStr { /// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err(); /// ``` #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "core_c_str", issue = "94079")] +#[stable(feature = "core_c_str", since = "1.64.0")] pub struct FromBytesWithNulError { kind: FromBytesWithNulErrorKind, } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 93cdf121fbe0f..ec1eaa99f0b8e 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -14,7 +14,7 @@ use crate::marker::PhantomData; use crate::num::*; use crate::ops::{Deref, DerefMut}; -#[unstable(feature = "core_c_str", issue = "94079")] +#[stable(feature = "core_c_str", since = "1.64.0")] pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError}; mod c_str; @@ -26,7 +26,7 @@ macro_rules! type_alias_no_nz { } => { #[doc = include_str!($Docfile)] $( $Cfg )* - #[unstable(feature = "core_ffi_c", issue = "94501")] + #[stable(feature = "core_ffi_c", since = "1.64.0")] pub type $Alias = $Real; } } @@ -231,7 +231,8 @@ impl fmt::Debug for c_void { all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), target_family = "wasm", target_arch = "asmjs", - windows + target_os = "uefi", + windows, ))] #[repr(transparent)] #[unstable( @@ -254,7 +255,8 @@ pub struct VaListImpl<'f> { all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), target_family = "wasm", target_arch = "asmjs", - windows + target_os = "uefi", + windows, ))] #[unstable( feature = "c_variadic", @@ -276,7 +278,8 @@ impl<'f> fmt::Debug for VaListImpl<'f> { #[cfg(all( target_arch = "aarch64", not(any(target_os = "macos", target_os = "ios")), - not(windows) + not(target_os = "uefi"), + not(windows), ))] #[repr(C)] #[derive(Debug)] @@ -297,7 +300,7 @@ pub struct VaListImpl<'f> { } /// PowerPC ABI implementation of a `va_list`. -#[cfg(all(target_arch = "powerpc", not(windows)))] +#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))] #[repr(C)] #[derive(Debug)] #[unstable( @@ -317,7 +320,7 @@ pub struct VaListImpl<'f> { } /// x86_64 ABI implementation of a `va_list`. -#[cfg(all(target_arch = "x86_64", not(windows)))] +#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))] #[repr(C)] #[derive(Debug)] #[unstable( @@ -354,7 +357,8 @@ pub struct VaList<'a, 'f: 'a> { all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), target_family = "wasm", target_arch = "asmjs", - windows + target_os = "uefi", + windows, ))] inner: VaListImpl<'f>, @@ -363,7 +367,8 @@ pub struct VaList<'a, 'f: 'a> { any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), not(target_family = "wasm"), not(target_arch = "asmjs"), - not(windows) + not(target_os = "uefi"), + not(windows), ))] inner: &'a mut VaListImpl<'f>, @@ -375,7 +380,8 @@ pub struct VaList<'a, 'f: 'a> { all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")), target_family = "wasm", target_arch = "asmjs", - windows + target_os = "uefi", + windows, ))] #[unstable( feature = "c_variadic", @@ -396,7 +402,8 @@ impl<'f> VaListImpl<'f> { any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))), not(target_family = "wasm"), not(target_arch = "asmjs"), - not(windows) + not(target_os = "uefi"), + not(windows), ))] #[unstable( feature = "c_variadic", diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 9e4a574818a14..6c3bb7229e51f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -4,6 +4,7 @@ use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell}; use crate::char::EscapeDebugExtArgs; +use crate::iter; use crate::marker::PhantomData; use crate::mem; use crate::num::fmt as numfmt; @@ -693,7 +694,7 @@ pub(crate) mod macros { /// Derive macro generating an impl of the trait `Debug`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] - #[allow_internal_unstable(core_intrinsics)] + #[allow_internal_unstable(core_intrinsics, fmt_helpers_for_derive)] pub macro Debug($item:item) { /* compiler built-in */ } @@ -1964,6 +1965,129 @@ impl<'a> Formatter<'a> { builders::debug_struct_new(self, name) } + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_struct_fields_finish` is more general, but this is faster for 1 field. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_struct_field1_finish<'b>( + &'b mut self, + name: &str, + name1: &str, + value1: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_struct_new(self, name); + builder.field(name1, value1); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_struct_fields_finish` is more general, but this is faster for 2 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_struct_field2_finish<'b>( + &'b mut self, + name: &str, + name1: &str, + value1: &dyn Debug, + name2: &str, + value2: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_struct_new(self, name); + builder.field(name1, value1); + builder.field(name2, value2); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_struct_fields_finish` is more general, but this is faster for 3 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_struct_field3_finish<'b>( + &'b mut self, + name: &str, + name1: &str, + value1: &dyn Debug, + name2: &str, + value2: &dyn Debug, + name3: &str, + value3: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_struct_new(self, name); + builder.field(name1, value1); + builder.field(name2, value2); + builder.field(name3, value3); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_struct_fields_finish` is more general, but this is faster for 4 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_struct_field4_finish<'b>( + &'b mut self, + name: &str, + name1: &str, + value1: &dyn Debug, + name2: &str, + value2: &dyn Debug, + name3: &str, + value3: &dyn Debug, + name4: &str, + value4: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_struct_new(self, name); + builder.field(name1, value1); + builder.field(name2, value2); + builder.field(name3, value3); + builder.field(name4, value4); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_struct_fields_finish` is more general, but this is faster for 5 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_struct_field5_finish<'b>( + &'b mut self, + name: &str, + name1: &str, + value1: &dyn Debug, + name2: &str, + value2: &dyn Debug, + name3: &str, + value3: &dyn Debug, + name4: &str, + value4: &dyn Debug, + name5: &str, + value5: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_struct_new(self, name); + builder.field(name1, value1); + builder.field(name2, value2); + builder.field(name3, value3); + builder.field(name4, value4); + builder.field(name5, value5); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// For the cases not covered by `debug_struct_field[12345]_finish`. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_struct_fields_finish<'b>( + &'b mut self, + name: &str, + names: &[&str], + values: &[&dyn Debug], + ) -> Result { + assert_eq!(names.len(), values.len()); + let mut builder = builders::debug_struct_new(self, name); + for (name, value) in iter::zip(names, values) { + builder.field(name, value); + } + builder.finish() + } + /// Creates a `DebugTuple` builder designed to assist with creation of /// `fmt::Debug` implementations for tuple structs. /// @@ -1995,6 +2119,108 @@ impl<'a> Formatter<'a> { builders::debug_tuple_new(self, name) } + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_tuple_fields_finish` is more general, but this is faster for 1 field. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_tuple_field1_finish<'b>(&'b mut self, name: &str, value1: &dyn Debug) -> Result { + let mut builder = builders::debug_tuple_new(self, name); + builder.field(value1); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_tuple_fields_finish` is more general, but this is faster for 2 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_tuple_field2_finish<'b>( + &'b mut self, + name: &str, + value1: &dyn Debug, + value2: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_tuple_new(self, name); + builder.field(value1); + builder.field(value2); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_tuple_fields_finish` is more general, but this is faster for 3 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_tuple_field3_finish<'b>( + &'b mut self, + name: &str, + value1: &dyn Debug, + value2: &dyn Debug, + value3: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_tuple_new(self, name); + builder.field(value1); + builder.field(value2); + builder.field(value3); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_tuple_fields_finish` is more general, but this is faster for 4 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_tuple_field4_finish<'b>( + &'b mut self, + name: &str, + value1: &dyn Debug, + value2: &dyn Debug, + value3: &dyn Debug, + value4: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_tuple_new(self, name); + builder.field(value1); + builder.field(value2); + builder.field(value3); + builder.field(value4); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// `debug_tuple_fields_finish` is more general, but this is faster for 5 fields. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_tuple_field5_finish<'b>( + &'b mut self, + name: &str, + value1: &dyn Debug, + value2: &dyn Debug, + value3: &dyn Debug, + value4: &dyn Debug, + value5: &dyn Debug, + ) -> Result { + let mut builder = builders::debug_tuple_new(self, name); + builder.field(value1); + builder.field(value2); + builder.field(value3); + builder.field(value4); + builder.field(value5); + builder.finish() + } + + /// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries. + /// For the cases not covered by `debug_tuple_field[12345]_finish`. + #[doc(hidden)] + #[unstable(feature = "fmt_helpers_for_derive", issue = "none")] + pub fn debug_tuple_fields_finish<'b>( + &'b mut self, + name: &str, + values: &[&dyn Debug], + ) -> Result { + let mut builder = builders::debug_tuple_new(self, name); + for value in values { + builder.field(value); + } + builder.finish() + } + /// Creates a `DebugList` builder designed to assist with creation of /// `fmt::Debug` implementations for list-like structures. /// @@ -2336,7 +2562,7 @@ macro_rules! tuple { macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(tuple_variadic))] + #[doc(tuple_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index ad9e80e117f1e..649b433877222 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -13,8 +13,6 @@ use crate::future::Future; /// on all futures. /// /// ```no_run -/// #![feature(into_future)] -/// /// use std::future::IntoFuture; /// /// # async fn foo() { @@ -33,8 +31,6 @@ use crate::future::Future; /// multiple times before being `.await`ed. /// /// ```rust -/// #![feature(into_future)] -/// /// use std::future::{ready, Ready, IntoFuture}; /// /// /// Eventually multiply two numbers @@ -91,8 +87,6 @@ use crate::future::Future; /// `IntoFuture::into_future` to obtain an instance of `Future`: /// /// ```rust -/// #![feature(into_future)] -/// /// use std::future::IntoFuture; /// /// /// Convert the output of a future to a string. @@ -104,14 +98,14 @@ use crate::future::Future; /// format!("{:?}", fut.await) /// } /// ``` -#[unstable(feature = "into_future", issue = "67644")] +#[stable(feature = "into_future", since = "1.64.0")] pub trait IntoFuture { /// The output that the future will produce on completion. - #[unstable(feature = "into_future", issue = "67644")] + #[stable(feature = "into_future", since = "1.64.0")] type Output; /// Which kind of future are we turning this into? - #[unstable(feature = "into_future", issue = "67644")] + #[stable(feature = "into_future", since = "1.64.0")] type IntoFuture: Future<Output = Self::Output>; /// Creates a future from a value. @@ -121,8 +115,6 @@ pub trait IntoFuture { /// Basic usage: /// /// ```no_run - /// #![feature(into_future)] - /// /// use std::future::IntoFuture; /// /// # async fn foo() { @@ -131,12 +123,12 @@ pub trait IntoFuture { /// assert_eq!("meow", fut.await); /// # } /// ``` - #[unstable(feature = "into_future", issue = "67644")] + #[stable(feature = "into_future", since = "1.64.0")] #[lang = "into_future"] fn into_future(self) -> Self::IntoFuture; } -#[unstable(feature = "into_future", issue = "67644")] +#[stable(feature = "into_future", since = "1.64.0")] impl<F: Future> IntoFuture for F { type Output = F::Output; type IntoFuture = F; diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index fa4eb0d2f33ee..35f0dea062ef9 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -15,7 +15,7 @@ use crate::task::{Context, Poll}; /// # Examples /// /// ``` -/// #![feature(future_join, future_poll_fn)] +/// #![feature(future_join)] /// /// use std::future::join; /// @@ -31,7 +31,7 @@ use crate::task::{Context, Poll}; /// `join!` is variadic, so you can pass any number of futures: /// /// ``` -/// #![feature(future_join, future_poll_fn)] +/// #![feature(future_join)] /// /// use std::future::join; /// diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 9b89f766c67bf..6487aa0885955 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -29,7 +29,7 @@ pub use self::future::Future; #[unstable(feature = "future_join", issue = "91642")] pub use self::join::join; -#[unstable(feature = "into_future", issue = "67644")] +#[stable(feature = "into_future", since = "1.64.0")] pub use into_future::IntoFuture; #[stable(feature = "future_readiness_fns", since = "1.48.0")] @@ -37,7 +37,7 @@ pub use pending::{pending, Pending}; #[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use ready::{ready, Ready}; -#[unstable(feature = "future_poll_fn", issue = "72302")] +#[stable(feature = "future_poll_fn", since = "1.64.0")] pub use poll_fn::{poll_fn, PollFn}; /// This type is needed because: diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 9ae118e29f110..db2a523323b7a 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -10,7 +10,6 @@ use crate::task::{Context, Poll}; /// # Examples /// /// ``` -/// #![feature(future_poll_fn)] /// # async fn run() { /// use core::future::poll_fn; /// use std::task::{Context, Poll}; @@ -23,7 +22,7 @@ use crate::task::{Context, Poll}; /// assert_eq!(read_future.await, "Hello, World!".to_owned()); /// # } /// ``` -#[unstable(feature = "future_poll_fn", issue = "72302")] +#[stable(feature = "future_poll_fn", since = "1.64.0")] pub fn poll_fn<T, F>(f: F) -> PollFn<F> where F: FnMut(&mut Context<'_>) -> Poll<T>, @@ -36,22 +35,22 @@ where /// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. #[must_use = "futures do nothing unless you `.await` or poll them"] -#[unstable(feature = "future_poll_fn", issue = "72302")] +#[stable(feature = "future_poll_fn", since = "1.64.0")] pub struct PollFn<F> { f: F, } -#[unstable(feature = "future_poll_fn", issue = "72302")] +#[stable(feature = "future_poll_fn", since = "1.64.0")] impl<F> Unpin for PollFn<F> {} -#[unstable(feature = "future_poll_fn", issue = "72302")] +#[stable(feature = "future_poll_fn", since = "1.64.0")] impl<F> fmt::Debug for PollFn<F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PollFn").finish() } } -#[unstable(feature = "future_poll_fn", issue = "72302")] +#[stable(feature = "future_poll_fn", since = "1.64.0")] impl<T, F> Future for PollFn<F> where F: FnMut(&mut Context<'_>) -> Poll<T>, diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 2c152fe1b2c18..cf428e0b1cf1d 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -180,7 +180,7 @@ mod sip; /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html /// [`hash`]: Hash::hash -/// [impl]: ../../std/primitive.str.html#impl-Hash +/// [impl]: ../../std/primitive.str.html#impl-Hash-for-str #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Hash"] pub trait Hash { @@ -900,7 +900,7 @@ mod impls { macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(tuple_variadic))] + #[doc(tuple_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 2f9afbec91e98..998f7be3f7396 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -63,6 +63,7 @@ use crate::mem; use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; #[stable(feature = "drop_in_place", since = "1.8.0")] +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] #[inline] pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { @@ -70,6 +71,214 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { unsafe { crate::ptr::drop_in_place(to_drop) } } +// These have been renamed. +#[cfg(bootstrap)] +extern "rust-intrinsic" { + pub fn atomic_cxchg<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_load<T: Copy>(src: *const T) -> T; + pub fn atomic_load_acq<T: Copy>(src: *const T) -> T; + pub fn atomic_load_relaxed<T: Copy>(src: *const T) -> T; + pub fn atomic_load_unordered<T: Copy>(src: *const T) -> T; + pub fn atomic_store<T: Copy>(dst: *mut T, val: T); + pub fn atomic_store_rel<T: Copy>(dst: *mut T, val: T); + pub fn atomic_store_relaxed<T: Copy>(dst: *mut T, val: T); + pub fn atomic_store_unordered<T: Copy>(dst: *mut T, val: T); + pub fn atomic_xchg<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_acqrel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_relaxed<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_fence(); + pub fn atomic_fence_acq(); + pub fn atomic_fence_rel(); + pub fn atomic_fence_acqrel(); + pub fn atomic_singlethreadfence(); + pub fn atomic_singlethreadfence_acq(); + pub fn atomic_singlethreadfence_rel(); + pub fn atomic_singlethreadfence_acqrel(); +} + +// These have been renamed. +#[cfg(bootstrap)] +mod atomics { + pub use super::atomic_cxchg as atomic_cxchg_seqcst_seqcst; + pub use super::atomic_cxchg_acq as atomic_cxchg_acquire_acquire; + pub use super::atomic_cxchg_acq_failrelaxed as atomic_cxchg_acquire_relaxed; + pub use super::atomic_cxchg_acqrel as atomic_cxchg_acqrel_acquire; + pub use super::atomic_cxchg_acqrel_failrelaxed as atomic_cxchg_acqrel_relaxed; + pub use super::atomic_cxchg_failacq as atomic_cxchg_seqcst_acquire; + pub use super::atomic_cxchg_failrelaxed as atomic_cxchg_seqcst_relaxed; + pub use super::atomic_cxchg_rel as atomic_cxchg_release_relaxed; + pub use super::atomic_cxchg_relaxed as atomic_cxchg_relaxed_relaxed; + + pub use super::atomic_cxchgweak as atomic_cxchgweak_seqcst_seqcst; + pub use super::atomic_cxchgweak_acq as atomic_cxchgweak_acquire_acquire; + pub use super::atomic_cxchgweak_acq_failrelaxed as atomic_cxchgweak_acquire_relaxed; + pub use super::atomic_cxchgweak_acqrel as atomic_cxchgweak_acqrel_acquire; + pub use super::atomic_cxchgweak_acqrel_failrelaxed as atomic_cxchgweak_acqrel_relaxed; + pub use super::atomic_cxchgweak_failacq as atomic_cxchgweak_seqcst_acquire; + pub use super::atomic_cxchgweak_failrelaxed as atomic_cxchgweak_seqcst_relaxed; + pub use super::atomic_cxchgweak_rel as atomic_cxchgweak_release_relaxed; + pub use super::atomic_cxchgweak_relaxed as atomic_cxchgweak_relaxed_relaxed; + + pub use super::atomic_load as atomic_load_seqcst; + pub use super::atomic_load_acq as atomic_load_acquire; + pub use super::atomic_load_relaxed; + pub use super::atomic_load_unordered; + + pub use super::atomic_store as atomic_store_seqcst; + pub use super::atomic_store_rel as atomic_store_release; + pub use super::atomic_store_relaxed; + pub use super::atomic_store_unordered; + + pub use super::atomic_xchg as atomic_xchg_seqcst; + pub use super::atomic_xchg_acq as atomic_xchg_acquire; + pub use super::atomic_xchg_acqrel; + pub use super::atomic_xchg_rel as atomic_xchg_release; + pub use super::atomic_xchg_relaxed; + + pub use super::atomic_xadd as atomic_xadd_seqcst; + pub use super::atomic_xadd_acq as atomic_xadd_acquire; + pub use super::atomic_xadd_acqrel; + pub use super::atomic_xadd_rel as atomic_xadd_release; + pub use super::atomic_xadd_relaxed; + + pub use super::atomic_xsub as atomic_xsub_seqcst; + pub use super::atomic_xsub_acq as atomic_xsub_acquire; + pub use super::atomic_xsub_acqrel; + pub use super::atomic_xsub_rel as atomic_xsub_release; + pub use super::atomic_xsub_relaxed; + + pub use super::atomic_and as atomic_and_seqcst; + pub use super::atomic_and_acq as atomic_and_acquire; + pub use super::atomic_and_acqrel; + pub use super::atomic_and_rel as atomic_and_release; + pub use super::atomic_and_relaxed; + + pub use super::atomic_nand as atomic_nand_seqcst; + pub use super::atomic_nand_acq as atomic_nand_acquire; + pub use super::atomic_nand_acqrel; + pub use super::atomic_nand_rel as atomic_nand_release; + pub use super::atomic_nand_relaxed; + + pub use super::atomic_or as atomic_or_seqcst; + pub use super::atomic_or_acq as atomic_or_acquire; + pub use super::atomic_or_acqrel; + pub use super::atomic_or_rel as atomic_or_release; + pub use super::atomic_or_relaxed; + + pub use super::atomic_xor as atomic_xor_seqcst; + pub use super::atomic_xor_acq as atomic_xor_acquire; + pub use super::atomic_xor_acqrel; + pub use super::atomic_xor_rel as atomic_xor_release; + pub use super::atomic_xor_relaxed; + + pub use super::atomic_max as atomic_max_seqcst; + pub use super::atomic_max_acq as atomic_max_acquire; + pub use super::atomic_max_acqrel; + pub use super::atomic_max_rel as atomic_max_release; + pub use super::atomic_max_relaxed; + + pub use super::atomic_min as atomic_min_seqcst; + pub use super::atomic_min_acq as atomic_min_acquire; + pub use super::atomic_min_acqrel; + pub use super::atomic_min_rel as atomic_min_release; + pub use super::atomic_min_relaxed; + + pub use super::atomic_umin as atomic_umin_seqcst; + pub use super::atomic_umin_acq as atomic_umin_acquire; + pub use super::atomic_umin_acqrel; + pub use super::atomic_umin_rel as atomic_umin_release; + pub use super::atomic_umin_relaxed; + + pub use super::atomic_umax as atomic_umax_seqcst; + pub use super::atomic_umax_acq as atomic_umax_acquire; + pub use super::atomic_umax_acqrel; + pub use super::atomic_umax_rel as atomic_umax_release; + pub use super::atomic_umax_relaxed; + + pub use super::atomic_fence as atomic_fence_seqcst; + pub use super::atomic_fence_acq as atomic_fence_acquire; + pub use super::atomic_fence_acqrel; + pub use super::atomic_fence_rel as atomic_fence_release; + + pub use super::atomic_singlethreadfence as atomic_singlethreadfence_seqcst; + pub use super::atomic_singlethreadfence_acq as atomic_singlethreadfence_acquire; + pub use super::atomic_singlethreadfence_acqrel; + pub use super::atomic_singlethreadfence_rel as atomic_singlethreadfence_release; +} + +#[cfg(bootstrap)] +pub use atomics::*; + +#[cfg(not(bootstrap))] extern "rust-intrinsic" { // N.B., these intrinsics take raw pointers because they mutate aliased // memory, which is not valid for either `&` or `&mut`. @@ -78,142 +287,226 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`] as both the `success` and `failure` parameters. + /// [`Ordering::Relaxed`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_relaxed_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`] as both the `success` and `failure` parameters. + /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_relaxed_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Release`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_relaxed_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Acquire`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_acquire_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Relaxed`] as both the `success` and `failure` parameters. + /// [`Ordering::Acquire`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acquire_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_acquire_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Acquire`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_release_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::Acquire`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_release_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing - /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange`]. - pub fn atomic_cxchg_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_release_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_acqrel_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_acqrel_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_acqrel_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_seqcst_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_seqcst_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange` method by passing + /// [`Ordering::SeqCst`] as both the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange`]. + pub fn atomic_cxchg_seqcst_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`] as both the `success` and `failure` parameters. + /// [`Ordering::Relaxed`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_relaxed_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`] as both the `success` and `failure` parameters. + /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_relaxed_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Release`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_relaxed_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Acquire`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_acquire_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Relaxed`] as both the `success` and `failure` parameters. + /// [`Ordering::Acquire`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acquire_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_acquire_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::SeqCst`] as the `success` and [`Ordering::Acquire`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_release_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::Acquire`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_release_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing - /// [`Ordering::AcqRel`] as the `success` and [`Ordering::Relaxed`] as the - /// `failure` parameters. For example, [`AtomicBool::compare_exchange_weak`]. - pub fn atomic_cxchgweak_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_release_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_acqrel_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_acqrel_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_acqrel_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_seqcst_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_seqcst_acquire<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); + /// Stores a value if the current value is the same as the `old` value. + /// + /// The stabilized version of this intrinsic is available on the + /// [`atomic`] types via the `compare_exchange_weak` method by passing + /// [`Ordering::SeqCst`] as both the success and failure parameters. + /// For example, [`AtomicBool::compare_exchange_weak`]. + pub fn atomic_cxchgweak_seqcst_seqcst<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. - pub fn atomic_load<T: Copy>(src: *const T) -> T; + pub fn atomic_load_seqcst<T: Copy>(src: *const T) -> T; /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. - pub fn atomic_load_acq<T: Copy>(src: *const T) -> T; + pub fn atomic_load_acquire<T: Copy>(src: *const T) -> T; /// Loads the current value of the pointer. /// /// The stabilized version of this intrinsic is available on the @@ -227,13 +520,13 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. - pub fn atomic_store<T: Copy>(dst: *mut T, val: T); + pub fn atomic_store_seqcst<T: Copy>(dst: *mut T, val: T); /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. - pub fn atomic_store_rel<T: Copy>(dst: *mut T, val: T); + pub fn atomic_store_release<T: Copy>(dst: *mut T, val: T); /// Stores the value at the specified memory location. /// /// The stabilized version of this intrinsic is available on the @@ -247,19 +540,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. - pub fn atomic_xchg<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. - pub fn atomic_xchg_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. - pub fn atomic_xchg_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_release<T: Copy>(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. /// /// The stabilized version of this intrinsic is available on the @@ -278,19 +571,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - pub fn atomic_xadd<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - pub fn atomic_xadd_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. - pub fn atomic_xadd_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_release<T: Copy>(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the @@ -309,19 +602,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - pub fn atomic_xsub<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - pub fn atomic_xsub_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. - pub fn atomic_xsub_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_release<T: Copy>(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the @@ -340,19 +633,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. - pub fn atomic_and<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. - pub fn atomic_and_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. - pub fn atomic_and_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_and_release<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the @@ -371,19 +664,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - pub fn atomic_nand<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - pub fn atomic_nand_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. - pub fn atomic_nand_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_nand_release<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the @@ -402,19 +695,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. - pub fn atomic_or<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. - pub fn atomic_or_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. - pub fn atomic_or_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_or_release<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the @@ -433,19 +726,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - pub fn atomic_xor<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - pub fn atomic_xor_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. - pub fn atomic_xor_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_xor_release<T: Copy>(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. /// /// The stabilized version of this intrinsic is available on the @@ -464,19 +757,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. - pub fn atomic_max<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. - pub fn atomic_max_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. - pub fn atomic_max_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_max_release<T: Copy>(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the @@ -495,19 +788,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. - pub fn atomic_min<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. - pub fn atomic_min_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. - pub fn atomic_min_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_min_release<T: Copy>(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. /// /// The stabilized version of this intrinsic is available on the @@ -526,19 +819,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. - pub fn atomic_umin<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. - pub fn atomic_umin_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. - pub fn atomic_umin_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umin_release<T: Copy>(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the @@ -557,19 +850,19 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. - pub fn atomic_umax<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_seqcst<T: Copy>(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. - pub fn atomic_umax_acq<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_acquire<T: Copy>(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. - pub fn atomic_umax_rel<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_umax_release<T: Copy>(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. /// /// The stabilized version of this intrinsic is available on the @@ -583,67 +876,24 @@ extern "rust-intrinsic" { /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. pub fn atomic_umax_relaxed<T: Copy>(dst: *mut T, src: T) -> T; - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - pub fn prefetch_read_data<T>(data: *const T, locality: i32); - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - pub fn prefetch_write_data<T>(data: *const T, locality: i32); - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - pub fn prefetch_read_instruction<T>(data: *const T, locality: i32); - /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a no-op. - /// Prefetches have no effect on the behavior of the program but can change its performance - /// characteristics. - /// - /// The `locality` argument must be a constant integer and is a temporal locality specifier - /// ranging from (0) - no locality, to (3) - extremely local keep in cache. - /// - /// This intrinsic does not have a stable counterpart. - pub fn prefetch_write_instruction<T>(data: *const T, locality: i32); -} - -extern "rust-intrinsic" { /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::SeqCst`] /// as the `order`. - pub fn atomic_fence(); + pub fn atomic_fence_seqcst(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::Acquire`] /// as the `order`. - pub fn atomic_fence_acq(); + pub fn atomic_fence_acquire(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::Release`] /// as the `order`. - pub fn atomic_fence_rel(); + pub fn atomic_fence_release(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in @@ -661,7 +911,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] /// as the `order`. - pub fn atomic_singlethreadfence(); + pub fn atomic_singlethreadfence_seqcst(); /// A compiler-only memory barrier. /// /// Memory accesses will never be reordered across this barrier by the @@ -672,7 +922,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] /// as the `order`. - pub fn atomic_singlethreadfence_acq(); + pub fn atomic_singlethreadfence_acquire(); /// A compiler-only memory barrier. /// /// Memory accesses will never be reordered across this barrier by the @@ -683,7 +933,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is available in /// [`atomic::compiler_fence`] by passing [`Ordering::Release`] /// as the `order`. - pub fn atomic_singlethreadfence_rel(); + pub fn atomic_singlethreadfence_release(); /// A compiler-only memory barrier. /// /// Memory accesses will never be reordered across this barrier by the @@ -695,6 +945,70 @@ extern "rust-intrinsic" { /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] /// as the `order`. pub fn atomic_singlethreadfence_acqrel(); +} + +// These have been renamed. +// +// These are the aliases for the old names. +// To be removed when stdarch and panic_unwind have been updated. +#[cfg(not(bootstrap))] +mod atomics { + pub use super::atomic_cxchg_acqrel_acquire as atomic_cxchg_acqrel; + pub use super::atomic_cxchg_acqrel_relaxed as atomic_cxchg_acqrel_failrelaxed; + pub use super::atomic_cxchg_acquire_acquire as atomic_cxchg_acq; + pub use super::atomic_cxchg_acquire_relaxed as atomic_cxchg_acq_failrelaxed; + pub use super::atomic_cxchg_relaxed_relaxed as atomic_cxchg_relaxed; + pub use super::atomic_cxchg_release_relaxed as atomic_cxchg_rel; + pub use super::atomic_cxchg_seqcst_acquire as atomic_cxchg_failacq; + pub use super::atomic_cxchg_seqcst_relaxed as atomic_cxchg_failrelaxed; + pub use super::atomic_cxchg_seqcst_seqcst as atomic_cxchg; + pub use super::atomic_store_seqcst as atomic_store; +} + +#[cfg(not(bootstrap))] +pub use atomics::*; + +extern "rust-intrinsic" { + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction + /// if supported; otherwise, it is a no-op. + /// Prefetches have no effect on the behavior of the program but can change its performance + /// characteristics. + /// + /// The `locality` argument must be a constant integer and is a temporal locality specifier + /// ranging from (0) - no locality, to (3) - extremely local keep in cache. + /// + /// This intrinsic does not have a stable counterpart. + pub fn prefetch_read_data<T>(data: *const T, locality: i32); + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction + /// if supported; otherwise, it is a no-op. + /// Prefetches have no effect on the behavior of the program but can change its performance + /// characteristics. + /// + /// The `locality` argument must be a constant integer and is a temporal locality specifier + /// ranging from (0) - no locality, to (3) - extremely local keep in cache. + /// + /// This intrinsic does not have a stable counterpart. + pub fn prefetch_write_data<T>(data: *const T, locality: i32); + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction + /// if supported; otherwise, it is a no-op. + /// Prefetches have no effect on the behavior of the program but can change its performance + /// characteristics. + /// + /// The `locality` argument must be a constant integer and is a temporal locality specifier + /// ranging from (0) - no locality, to (3) - extremely local keep in cache. + /// + /// This intrinsic does not have a stable counterpart. + pub fn prefetch_read_instruction<T>(data: *const T, locality: i32); + /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction + /// if supported; otherwise, it is a no-op. + /// Prefetches have no effect on the behavior of the program but can change its performance + /// characteristics. + /// + /// The `locality` argument must be a constant integer and is a temporal locality specifier + /// ranging from (0) - no locality, to (3) - extremely local keep in cache. + /// + /// This intrinsic does not have a stable counterpart. + pub fn prefetch_write_instruction<T>(data: *const T, locality: i32); /// Magic intrinsic that derives its meaning from attributes /// attached to the function. @@ -1144,6 +1458,7 @@ extern "rust-intrinsic" { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] pub fn transmute<T, U>(e: T) -> U; @@ -2043,6 +2358,9 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but /// with the argument order swapped. /// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy /// /// # Safety @@ -2118,6 +2436,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { @@ -2148,6 +2467,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us /// order swapped. Copying takes place as if the bytes were copied from `src` /// to a temporary array and then copied from the array to `dst`. /// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove /// /// # Safety @@ -2200,6 +2522,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { @@ -2289,6 +2612,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)] #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline] pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { @@ -2330,6 +2654,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { /// Here is an example of how this could cause a problem: /// ```no_run /// #![feature(const_eval_select)] +/// #![feature(core_intrinsics)] /// use std::hint::unreachable_unchecked; /// use std::intrinsics::const_eval_select; /// diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 53e48500e3b4d..60eb3a6da3a4b 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -37,33 +37,6 @@ impl<A, B> Chain<A, B> { } } -/// Fuse the iterator if the expression is `None`. -macro_rules! fuse { - ($self:ident . $iter:ident . $($call:tt)+) => { - match $self.$iter { - Some(ref mut iter) => match iter.$($call)+ { - None => { - $self.$iter = None; - None - } - item => item, - }, - None => None, - } - }; -} - -/// Try an iterator method without fusing, -/// like an inline `.as_mut().and_then(...)` -macro_rules! maybe { - ($self:ident . $iter:ident . $($call:tt)+) => { - match $self.$iter { - Some(ref mut iter) => iter.$($call)+, - None => None, - } - }; -} - #[stable(feature = "rust1", since = "1.0.0")] impl<A, B> Iterator for Chain<A, B> where @@ -74,10 +47,7 @@ where #[inline] fn next(&mut self) -> Option<A::Item> { - match fuse!(self.a.next()) { - None => maybe!(self.b.next()), - item => item, - } + and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next()) } #[inline] @@ -161,7 +131,7 @@ where self.a = None; } - maybe!(self.b.nth(n)) + self.b.as_mut()?.nth(n) } #[inline] @@ -169,23 +139,15 @@ where where P: FnMut(&Self::Item) -> bool, { - match fuse!(self.a.find(&mut predicate)) { - None => maybe!(self.b.find(predicate)), - item => item, - } + and_then_or_clear(&mut self.a, |a| a.find(&mut predicate)) + .or_else(|| self.b.as_mut()?.find(predicate)) } #[inline] fn last(self) -> Option<A::Item> { // Must exhaust a before b. - let a_last = match self.a { - Some(a) => a.last(), - None => None, - }; - let b_last = match self.b { - Some(b) => b.last(), - None => None, - }; + let a_last = self.a.and_then(Iterator::last); + let b_last = self.b.and_then(Iterator::last); b_last.or(a_last) } @@ -220,10 +182,7 @@ where { #[inline] fn next_back(&mut self) -> Option<A::Item> { - match fuse!(self.b.next_back()) { - None => maybe!(self.a.next_back()), - item => item, - } + and_then_or_clear(&mut self.b, |b| b.next_back()).or_else(|| self.a.as_mut()?.next_back()) } #[inline] @@ -263,7 +222,7 @@ where self.b = None; } - maybe!(self.a.nth_back(n)) + self.a.as_mut()?.nth_back(n) } #[inline] @@ -271,10 +230,8 @@ where where P: FnMut(&Self::Item) -> bool, { - match fuse!(self.b.rfind(&mut predicate)) { - None => maybe!(self.a.rfind(predicate)), - item => item, - } + and_then_or_clear(&mut self.b, |b| b.rfind(&mut predicate)) + .or_else(|| self.a.as_mut()?.rfind(predicate)) } fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R @@ -324,3 +281,12 @@ where B: TrustedLen<Item = A::Item>, { } + +#[inline] +fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> { + let x = f(opt.as_mut()?); + if x.is_none() { + *opt = None; + } + x +} diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 351fd569d8acf..15a120e35a2fa 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -290,20 +290,11 @@ where #[inline] fn next(&mut self) -> Option<U::Item> { loop { - if let Some(ref mut inner) = self.frontiter { - match inner.next() { - None => self.frontiter = None, - elt @ Some(_) => return elt, - } + if let elt @ Some(_) = and_then_or_clear(&mut self.frontiter, Iterator::next) { + return elt; } match self.iter.next() { - None => match self.backiter.as_mut()?.next() { - None => { - self.backiter = None; - return None; - } - elt @ Some(_) => return elt, - }, + None => return and_then_or_clear(&mut self.backiter, Iterator::next), Some(inner) => self.frontiter = Some(inner.into_iter()), } } @@ -436,21 +427,12 @@ where #[inline] fn next_back(&mut self) -> Option<U::Item> { loop { - if let Some(ref mut inner) = self.backiter { - match inner.next_back() { - None => self.backiter = None, - elt @ Some(_) => return elt, - } + if let elt @ Some(_) = and_then_or_clear(&mut self.backiter, |b| b.next_back()) { + return elt; } match self.iter.next_back() { - None => match self.frontiter.as_mut()?.next_back() { - None => { - self.frontiter = None; - return None; - } - elt @ Some(_) => return elt, - }, - next => self.backiter = next.map(IntoIterator::into_iter), + None => return and_then_or_clear(&mut self.frontiter, |f| f.next_back()), + Some(inner) => self.backiter = Some(inner.into_iter()), } } } @@ -606,3 +588,12 @@ unsafe impl<T, const N: usize> TrustedConstSize for [T; N] {} unsafe impl<T, const N: usize> TrustedConstSize for &'_ [T; N] {} #[unstable(feature = "std_internals", issue = "none")] unsafe impl<T, const N: usize> TrustedConstSize for &'_ mut [T; N] {} + +#[inline] +fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> { + let x = f(opt.as_mut()?); + if x.is_none() { + *opt = None; + } + x +} diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index 8adb53c671428..c931445420342 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -29,33 +29,6 @@ impl<I> Fuse<I> { #[stable(feature = "fused", since = "1.26.0")] impl<I> FusedIterator for Fuse<I> where I: Iterator {} -/// Fuse the iterator if the expression is `None`. -macro_rules! fuse { - ($self:ident . iter . $($call:tt)+) => { - match $self.iter { - Some(ref mut iter) => match iter.$($call)+ { - None => { - $self.iter = None; - None - } - item => item, - }, - None => None, - } - }; -} - -/// Specialized macro that doesn't check if the expression is `None`. -/// (We trust that a `FusedIterator` will fuse itself.) -macro_rules! spec { - ($self:ident . iter . $($call:tt)+) => { - match $self.iter { - Some(ref mut iter) => iter.$($call)+, - None => None, - } - }; -} - // Any specialized implementation here is made internal // to avoid exposing default fns outside this trait. #[stable(feature = "rust1", since = "1.0.0")] @@ -281,12 +254,12 @@ where #[inline] default fn next(&mut self) -> Option<<I as Iterator>::Item> { - fuse!(self.iter.next()) + and_then_or_clear(&mut self.iter, Iterator::next) } #[inline] default fn nth(&mut self, n: usize) -> Option<I::Item> { - fuse!(self.iter.nth(n)) + and_then_or_clear(&mut self.iter, |iter| iter.nth(n)) } #[inline] @@ -308,7 +281,7 @@ where where P: FnMut(&Self::Item) -> bool, { - fuse!(self.iter.find(predicate)) + and_then_or_clear(&mut self.iter, |iter| iter.find(predicate)) } #[inline] @@ -316,7 +289,7 @@ where where I: DoubleEndedIterator, { - fuse!(self.iter.next_back()) + and_then_or_clear(&mut self.iter, |iter| iter.next_back()) } #[inline] @@ -324,7 +297,7 @@ where where I: DoubleEndedIterator, { - fuse!(self.iter.nth_back(n)) + and_then_or_clear(&mut self.iter, |iter| iter.nth_back(n)) } #[inline] @@ -348,7 +321,7 @@ where P: FnMut(&Self::Item) -> bool, I: DoubleEndedIterator, { - fuse!(self.iter.rfind(predicate)) + and_then_or_clear(&mut self.iter, |iter| iter.rfind(predicate)) } } @@ -361,12 +334,12 @@ where { #[inline] fn next(&mut self) -> Option<<I as Iterator>::Item> { - spec!(self.iter.next()) + self.iter.as_mut()?.next() } #[inline] fn nth(&mut self, n: usize) -> Option<I::Item> { - spec!(self.iter.nth(n)) + self.iter.as_mut()?.nth(n) } #[inline] @@ -387,7 +360,7 @@ where where P: FnMut(&Self::Item) -> bool, { - spec!(self.iter.find(predicate)) + self.iter.as_mut()?.find(predicate) } #[inline] @@ -395,7 +368,7 @@ where where I: DoubleEndedIterator, { - spec!(self.iter.next_back()) + self.iter.as_mut()?.next_back() } #[inline] @@ -403,7 +376,7 @@ where where I: DoubleEndedIterator, { - spec!(self.iter.nth_back(n)) + self.iter.as_mut()?.nth_back(n) } #[inline] @@ -426,6 +399,15 @@ where P: FnMut(&Self::Item) -> bool, I: DoubleEndedIterator, { - spec!(self.iter.rfind(predicate)) + self.iter.as_mut()?.rfind(predicate) + } +} + +#[inline] +fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> { + let x = f(opt.as_mut()?); + if x.is_none() { + *opt = None; } + x } diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index a476799b70d6c..1757e37ec0e2f 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -66,13 +66,15 @@ /// /// // And now we can use it! /// -/// let counter = Counter::new(); +/// let mut counter = Counter::new(); /// /// assert_eq!(5, counter.len()); +/// let _ = counter.next(); +/// assert_eq!(4, counter.len()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait ExactSizeIterator: Iterator { - /// Returns the exact length of the iterator. + /// Returns the exact remaining length of the iterator. /// /// The implementation ensures that the iterator will return exactly `len()` /// more times a [`Some(T)`] value, before returning [`None`]. @@ -93,9 +95,11 @@ pub trait ExactSizeIterator: Iterator { /// /// ``` /// // a finite range knows exactly how many times it will iterate - /// let five = 0..5; + /// let mut range = 0..5; /// - /// assert_eq!(5, five.len()); + /// assert_eq!(5, range.len()); + /// let _ = range.next(); + /// assert_eq!(4, range.len()); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 1cc9133fc3dc4..275412b57b55f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,3 +1,4 @@ +use crate::array; use crate::cmp::{self, Ordering}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; @@ -102,6 +103,47 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option<Self::Item>; + /// Advances the iterator and returns an array containing the next `N` values. + /// + /// If there are not enough elements to fill the array then `Err` is returned + /// containing an iterator over the remaining elements. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_next_chunk)] + /// + /// let mut iter = "lorem".chars(); + /// + /// assert_eq!(iter.next_chunk().unwrap(), ['l', 'o']); // N is inferred as 2 + /// assert_eq!(iter.next_chunk().unwrap(), ['r', 'e', 'm']); // N is inferred as 3 + /// assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4 + /// ``` + /// + /// Split a string and get the first three items. + /// + /// ``` + /// #![feature(iter_next_chunk)] + /// + /// let quote = "not all those who wander are lost"; + /// let [first, second, third] = quote.split_whitespace().next_chunk().unwrap(); + /// assert_eq!(first, "not"); + /// assert_eq!(second, "all"); + /// assert_eq!(third, "those"); + /// ``` + #[inline] + #[unstable(feature = "iter_next_chunk", reason = "recently added", issue = "98326")] + fn next_chunk<const N: usize>( + &mut self, + ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> + where + Self: Sized, + { + array::iter_next_chunk(self) + } + /// Returns the bounds on the remaining length of the iterator. /// /// Specifically, `size_hint()` returns a tuple where the first element @@ -135,9 +177,11 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// let iter = a.iter(); + /// let mut iter = a.iter(); /// /// assert_eq!((3, Some(3)), iter.size_hint()); + /// let _ = iter.next(); + /// assert_eq!((2, Some(2)), iter.size_hint()); /// ``` /// /// A more complex example: diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 093c7d298734a..f24a7ab61ae89 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -134,7 +134,7 @@ #![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] -#![feature(const_slice_from_raw_parts)] +#![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_ptr_len)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_swap)] @@ -191,7 +191,6 @@ #![feature(never_type)] #![feature(no_core)] #![feature(no_coverage)] // rust-lang/rust#84605 -#![feature(no_niche)] // rust-lang/rust#68303 #![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(repr_simd)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 673a39c298f7d..bd62bc5c3056c 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1537,7 +1537,7 @@ pub(crate) mod builtin { /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, libstd_sys_internals)] + #[allow_internal_unstable(core_intrinsics, libstd_sys_internals, rt)] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcDecodable($item:item) { @@ -1547,7 +1547,7 @@ pub(crate) mod builtin { /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics)] + #[allow_internal_unstable(core_intrinsics, rt)] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcEncodable($item:item) { diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs index fcfa95120df21..4ce6d13cf9027 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -1,4 +1,5 @@ use crate::convert::TryFrom; +use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -26,7 +27,8 @@ impl ValidAlign { /// It must *not* be zero. #[inline] pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - debug_assert!(align.is_power_of_two()); + // SAFETY: Precondition passed to the caller. + unsafe { assert_unsafe_precondition!(align.is_power_of_two()) }; // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. @@ -46,6 +48,13 @@ impl ValidAlign { pub(crate) fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() } + + /// Returns the alignment for a type. + #[inline] + pub(crate) fn of<T>() -> Self { + // SAFETY: rustc ensures that type alignment is always a power of two. + unsafe { ValidAlign::new_unchecked(mem::align_of::<T>()) } + } } impl fmt::Debug for ValidAlign { diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 1f435784be14c..147f04a3f125d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2,9 +2,10 @@ macro_rules! int_impl { ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $BITS_MINUS_ONE:expr, $Min:expr, $Max:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, - $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { - /// The smallest value that can be represented by this integer type, - #[doc = concat!("−2<sup>", $BITS_MINUS_ONE, "</sup>.")] + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr, + $bound_condition:expr) => { + /// The smallest value that can be represented by this integer type + #[doc = concat!("(−2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ")")] /// /// # Examples /// @@ -16,8 +17,8 @@ macro_rules! int_impl { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; - /// The largest value that can be represented by this integer type, - #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> − 1.")] + /// The largest value that can be represented by this integer type + #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> − 1", $bound_condition, ")")] /// /// # Examples /// diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 66193eaf5da73..f481399fdcf92 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -196,25 +196,25 @@ macro_rules! widening_impl { impl i8 { int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", - "[0x12]", "[0x12]", "", "" } + "[0x12]", "[0x12]", "", "", "" } } impl i16 { int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", - "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } + "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "", "" } } impl i32 { int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]", "", "" } + "[0x12, 0x34, 0x56, 0x78]", "", "", "" } } impl i64 { int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "", "" } } impl i128 { @@ -225,14 +225,15 @@ impl i128 { "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "", "" } } #[cfg(target_pointer_width = "16")] impl isize { int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(), + " on 16-bit targets" } } #[cfg(target_pointer_width = "32")] @@ -240,7 +241,8 @@ impl isize { int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(), + " on 32-bit targets" } } #[cfg(target_pointer_width = "64")] @@ -249,7 +251,8 @@ impl isize { 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(), + " on 64-bit targets" } } /// If 6th bit set ascii is upper case. @@ -257,7 +260,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000; impl u8 { uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", - "[0x12]", "", "" } + "[0x12]", "", "", "" } widening_impl! { u8, u16, 8, unsigned } /// Checks if the value is within the ASCII range. @@ -810,7 +813,7 @@ impl u8 { impl u16 { uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", - "[0x34, 0x12]", "[0x12, 0x34]", "", "" } + "[0x34, 0x12]", "[0x12, 0x34]", "", "", "" } widening_impl! { u16, u32, 16, unsigned } /// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`]. @@ -841,7 +844,7 @@ impl u16 { impl u32 { uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", - "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } + "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "", "" } widening_impl! { u32, u64, 32, unsigned } } @@ -850,7 +853,7 @@ impl u64 { "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", - "", ""} + "", "", ""} widening_impl! { u64, u128, 64, unsigned } } @@ -862,21 +865,23 @@ impl u128 { 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", - "", ""} + "", "", ""} } #[cfg(target_pointer_width = "16")] impl usize { uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(), + " on 16-bit targets" } widening_impl! { usize, u32, 16, unsigned } } #[cfg(target_pointer_width = "32")] impl usize { uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(), + " on 32-bit targets" } widening_impl! { usize, u64, 32, unsigned } } @@ -886,7 +891,8 @@ impl usize { "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", - usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(), + " on 64-bit targets" } widening_impl! { usize, u128, 64, unsigned } } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 70969edd6eaf7..92d03b724b40e 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -213,7 +213,7 @@ macro_rules! nonzero_leading_trailing_zeros { without modifying the original"] #[inline] pub const fn leading_zeros(self) -> u32 { - // SAFETY: since `self` can not be zero it is safe to call ctlz_nonzero + // SAFETY: since `self` cannot be zero, it is safe to call `ctlz_nonzero`. unsafe { intrinsics::ctlz_nonzero(self.0 as $Uint) as u32 } } @@ -237,7 +237,7 @@ macro_rules! nonzero_leading_trailing_zeros { without modifying the original"] #[inline] pub const fn trailing_zeros(self) -> u32 { - // SAFETY: since `self` can not be zero it is safe to call cttz_nonzero + // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`. unsafe { intrinsics::cttz_nonzero(self.0 as $Uint) as u32 } } @@ -316,7 +316,6 @@ macro_rules! nonzero_unsigned_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -331,7 +330,8 @@ macro_rules! nonzero_unsigned_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -351,7 +351,6 @@ macro_rules! nonzero_unsigned_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -366,7 +365,8 @@ macro_rules! nonzero_unsigned_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -415,7 +415,6 @@ macro_rules! nonzero_unsigned_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -432,7 +431,8 @@ macro_rules! nonzero_unsigned_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -521,7 +521,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -534,7 +533,8 @@ macro_rules! nonzero_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -551,7 +551,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -566,7 +565,8 @@ macro_rules! nonzero_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -586,7 +586,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -602,7 +601,8 @@ macro_rules! nonzero_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -621,7 +621,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -642,7 +641,8 @@ macro_rules! nonzero_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -657,7 +657,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -677,7 +676,8 @@ macro_rules! nonzero_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -692,7 +692,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("# use std::num::", stringify!($Uty), ";")] /// @@ -712,7 +711,8 @@ macro_rules! nonzero_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -746,7 +746,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -761,7 +760,8 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -782,7 +782,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -797,7 +796,8 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -855,7 +855,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -870,7 +869,8 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -899,7 +899,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Examples /// /// ``` - /// #![feature(nonzero_ops)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// /// # fn main() { test().unwrap(); } @@ -914,7 +913,8 @@ macro_rules! nonzero_unsigned_signed_operations { /// # Some(()) /// # } /// ``` - #[unstable(feature = "nonzero_ops", issue = "84186")] + #[stable(feature = "nonzero_checked_ops", since = "1.64.0")] + #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cd4b0e18c4dff..715e78350a499 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -3,7 +3,8 @@ macro_rules! uint_impl { $BITS:expr, $MaxV:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, - $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr, + $bound_condition:expr) => { /// The smallest value that can be represented by this integer type. /// /// # Examples @@ -16,8 +17,8 @@ macro_rules! uint_impl { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const MIN: Self = 0; - /// The largest value that can be represented by this integer type, - #[doc = concat!("2<sup>", $BITS, "</sup> − 1.")] + /// The largest value that can be represented by this integer type + #[doc = concat!("(2<sup>", $BITS, "</sup> − 1", $bound_condition, ")")] /// /// # Examples /// diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 28ea45ed235dc..bca73cb770fbb 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -389,7 +389,7 @@ //! [`Option`] of a collection of each contained value of the original //! [`Option`] values, or [`None`] if any of the elements was [`None`]. //! -//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E +//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E-for-Option%3CV%3E //! //! ``` //! let v = [Some(2), Some(4), None, Some(8)]; @@ -405,8 +405,8 @@ //! to provide the [`product`][Iterator::product] and //! [`sum`][Iterator::sum] methods. //! -//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E -//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E +//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E-for-Option%3CT%3E +//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E-for-Option%3CT%3E //! //! ``` //! let v = [None, Some(1), Some(2), Some(3)]; diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index f2948aac3c235..9a6153f1253c5 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -217,7 +217,7 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {} #[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {} #[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[unstable(feature = "integer_atomics", issue = "99069")] impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {} #[cfg(target_has_atomic_load_store = "ptr")] @@ -236,7 +236,7 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {} #[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {} #[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[unstable(feature = "integer_atomics", issue = "99069")] impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {} #[cfg(target_has_atomic_load_store = "8")] diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 00793f7f9204d..401c8159988bb 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -996,7 +996,7 @@ impl<T> (T,) {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(tuple_variadic))] +#[doc(tuple_variadic)] /// This trait is implemented on arbitrary-length tuples. impl<T: Clone> Clone for (T,) { fn clone(&self) -> Self { @@ -1007,7 +1007,7 @@ impl<T: Clone> Clone for (T,) { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(tuple_variadic))] +#[doc(tuple_variadic)] /// This trait is implemented on arbitrary-length tuples. impl<T: Copy> Copy for (T,) { // empty diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8fb0bfbe2e31b..509854225c4f3 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -492,27 +492,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { unsafe { drop_in_place(to_drop) } } -/// Creates a null raw pointer. -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let p: *const i32 = ptr::null(); -/// assert!(p.is_null()); -/// ``` -#[inline(always)] -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] -#[rustc_diagnostic_item = "ptr_null"] -#[cfg(bootstrap)] -pub const fn null<T>() -> *const T { - invalid(0) -} - /// Creates a null raw pointer. /// /// # Examples @@ -530,32 +509,10 @@ pub const fn null<T>() -> *const T { #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null"] -#[cfg(not(bootstrap))] pub const fn null<T: ?Sized + Thin>() -> *const T { from_raw_parts(invalid(0), ()) } -/// Creates a null mutable raw pointer. -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// -/// let p: *mut i32 = ptr::null_mut(); -/// assert!(p.is_null()); -/// ``` -#[inline(always)] -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_promotable] -#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] -#[rustc_diagnostic_item = "ptr_null_mut"] -#[cfg(bootstrap)] -pub const fn null_mut<T>() -> *mut T { - invalid_mut(0) -} - /// Creates an invalid pointer with the given address. /// /// This is different from `addr as *const T`, which creates a pointer that picks up a previously @@ -707,7 +664,6 @@ where #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null_mut"] -#[cfg(not(bootstrap))] pub const fn null_mut<T: ?Sized + Thin>() -> *mut T { from_raw_parts_mut(invalid_mut(0), ()) } @@ -734,7 +690,8 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T { /// ``` #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] +#[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] { from_raw_parts(data.cast(), len) } @@ -766,7 +723,7 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] { /// ``` #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] +#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { from_raw_parts_mut(data.cast(), len) } @@ -774,7 +731,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { /// Swaps the values at two mutable locations of the same type, without /// deinitializing either. /// -/// But for the following two exceptions, this function is semantically +/// But for the following exceptions, this function is semantically /// equivalent to [`mem::swap`]: /// /// * It operates on raw pointers instead of references. When references are @@ -784,6 +741,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { /// overlapping region of memory from `x` will be used. This is demonstrated /// in the second example below. /// +/// * The operation is "untyped" in the sense that data may be uninitialized or otherwise violate +/// the requirements of `T`. The initialization state is preserved exactly. +/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -860,6 +820,9 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) { /// Swaps `count * size_of::<T>()` bytes between the two regions of memory /// beginning at `x` and `y`. The two regions must *not* overlap. /// +/// The operation is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -905,15 +868,15 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { if mem::align_of::<T>() >= mem::align_of::<$ChunkTy>() && mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0 { - let x: *mut MaybeUninit<$ChunkTy> = x.cast(); - let y: *mut MaybeUninit<$ChunkTy> = y.cast(); + let x: *mut $ChunkTy = x.cast(); + let y: *mut $ChunkTy = y.cast(); let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>()); // SAFETY: these are the same bytes that the caller promised were // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s. // The `if` condition above ensures that we're not violating // alignment requirements, and that the division is exact so // that we don't lose any bytes off the end. - return unsafe { swap_nonoverlapping_simple(x, y, count) }; + return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }; } }; } @@ -946,7 +909,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { } // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple(x, y, count) } + unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } } /// Same behaviour and safety conditions as [`swap_nonoverlapping`] @@ -955,17 +918,17 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] -const unsafe fn swap_nonoverlapping_simple<T>(x: *mut T, y: *mut T, count: usize) { +const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, count: usize) { + let x = x.cast::<MaybeUninit<T>>(); + let y = y.cast::<MaybeUninit<T>>(); let mut i = 0; while i < count { - let x: &mut T = - // SAFETY: By precondition, `i` is in-bounds because it's below `n` - unsafe { &mut *x.add(i) }; - let y: &mut T = - // SAFETY: By precondition, `i` is in-bounds because it's below `n` - // and it's distinct from `x` since the ranges are non-overlapping - unsafe { &mut *y.add(i) }; - mem::swap_simple(x, y); + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + let x = unsafe { &mut *x.add(i) }; + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + // and it's distinct from `x` since the ranges are non-overlapping + let y = unsafe { &mut *y.add(i) }; + mem::swap_simple::<MaybeUninit<T>>(x, y); i += 1; } @@ -1594,11 +1557,10 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= // 1, where the method versions of these operations are not inlined. use intrinsics::{ - unchecked_shl, unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub, + cttz_nonzero, exact_div, unchecked_rem, unchecked_shl, unchecked_shr, unchecked_sub, + wrapping_add, wrapping_mul, wrapping_sub, }; - let addr = p.addr(); - /// Calculate multiplicative modular inverse of `x` modulo `m`. /// /// This implementation is tailored for `align_offset` and has following preconditions: @@ -1648,36 +1610,61 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { } } + let addr = p.addr(); let stride = mem::size_of::<T>(); // SAFETY: `a` is a power-of-two, therefore non-zero. let a_minus_one = unsafe { unchecked_sub(a, 1) }; - if stride == 1 { - // `stride == 1` case can be computed more simply through `-p (mod a)`, but doing so - // inhibits LLVM's ability to select instructions like `lea`. Instead we compute + + if stride == 0 { + // SPECIAL_CASE: handle 0-sized types. No matter how many times we step, the address will + // stay the same, so no offset will be able to align the pointer unless it is already + // aligned. This branch _will_ be optimized out as `stride` is known at compile-time. + let p_mod_a = addr & a_minus_one; + return if p_mod_a == 0 { 0 } else { usize::MAX }; + } + + // SAFETY: `stride == 0` case has been handled by the special case above. + let a_mod_stride = unsafe { unchecked_rem(a, stride) }; + if a_mod_stride == 0 { + // SPECIAL_CASE: In cases where the `a` is divisible by `stride`, byte offset to align a + // pointer can be computed more simply through `-p (mod a)`. In the off-chance the byte + // offset is not a multiple of `stride`, the input pointer was misaligned and no pointer + // offset will be able to produce a `p` aligned to the specified `a`. // - // round_up_to_next_alignment(p, a) - p + // The naive `-p (mod a)` equation inhibits LLVM's ability to select instructions + // like `lea`. We compute `(round_up_to_next_alignment(p, a) - p)` instead. This + // redistributes operations around the load-bearing, but pessimizing `and` instruction + // sufficiently for LLVM to be able to utilize the various optimizations it knows about. // - // which distributes operations around the load-bearing, but pessimizing `and` sufficiently - // for LLVM to be able to utilize the various optimizations it knows about. - return wrapping_sub(wrapping_add(addr, a_minus_one) & wrapping_sub(0, a), addr); - } + // LLVM handles the branch here particularly nicely. If this branch needs to be evaluated + // at runtime, it will produce a mask `if addr_mod_stride == 0 { 0 } else { usize::MAX }` + // in a branch-free way and then bitwise-OR it with whatever result the `-p mod a` + // computation produces. + + // SAFETY: `stride == 0` case has been handled by the special case above. + let addr_mod_stride = unsafe { unchecked_rem(addr, stride) }; - let pmoda = addr & a_minus_one; - if pmoda == 0 { - // Already aligned. Yay! - return 0; - } else if stride == 0 { - // If the pointer is not aligned, and the element is zero-sized, then no amount of - // elements will ever align the pointer. - return usize::MAX; + return if addr_mod_stride == 0 { + let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a); + let byte_offset = wrapping_sub(aligned_address, addr); + // SAFETY: `stride` is non-zero. This is guaranteed to divide exactly as well, because + // addr has been verified to be aligned to the original type’s alignment requirements. + unsafe { exact_div(byte_offset, stride) } + } else { + usize::MAX + }; } - let smoda = stride & a_minus_one; + // GENERAL_CASE: From here on we’re handling the very general case where `addr` may be + // misaligned, there isn’t an obvious relationship between `stride` and `a` that we can take an + // advantage of, etc. This case produces machine code that isn’t particularly high quality, + // compared to the special cases above. The code produced here is still within the realm of + // miracles, given the situations this case has to deal with. + // SAFETY: a is power-of-two hence non-zero. stride == 0 case is handled above. - let gcdpow = unsafe { intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)) }; + let gcdpow = unsafe { cttz_nonzero(stride).min(cttz_nonzero(a)) }; // SAFETY: gcdpow has an upper-bound that’s at most the number of bits in a usize. let gcd = unsafe { unchecked_shl(1usize, gcdpow) }; - // SAFETY: gcd is always greater or equal to 1. if addr & unsafe { unchecked_sub(gcd, 1) } == 0 { // This branch solves for the following linear congruence equation: @@ -1693,14 +1680,13 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { // ` p' + s'o = 0 mod a' ` // ` o = (a' - (p' mod a')) * (s'^-1 mod a') ` // - // The first term is "the relative alignment of `p` to `a`" (divided by the `g`), the second - // term is "how does incrementing `p` by `s` bytes change the relative alignment of `p`" (again - // divided by `g`). - // Division by `g` is necessary to make the inverse well formed if `a` and `s` are not - // co-prime. + // The first term is "the relative alignment of `p` to `a`" (divided by the `g`), the + // second term is "how does incrementing `p` by `s` bytes change the relative alignment of + // `p`" (again divided by `g`). Division by `g` is necessary to make the inverse well + // formed if `a` and `s` are not co-prime. // // Furthermore, the result produced by this solution is not "minimal", so it is necessary - // to take the result `o mod lcm(s, a)`. We can replace `lcm(s, a)` with just a `a'`. + // to take the result `o mod lcm(s, a)`. This `lcm(s, a)` is the same as `a'`. // SAFETY: `gcdpow` has an upper-bound not greater than the number of trailing 0-bits in // `a`. @@ -1710,11 +1696,11 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { let a2minus1 = unsafe { unchecked_sub(a2, 1) }; // SAFETY: `gcdpow` has an upper-bound not greater than the number of trailing 0-bits in // `a`. - let s2 = unsafe { unchecked_shr(smoda, gcdpow) }; + let s2 = unsafe { unchecked_shr(stride & a_minus_one, gcdpow) }; // SAFETY: `gcdpow` has an upper-bound not greater than the number of trailing 0-bits in // `a`. Furthermore, the subtraction cannot overflow, because `a2 = a >> gcdpow` will // always be strictly greater than `(p % a) >> gcdpow`. - let minusp2 = unsafe { unchecked_sub(a2, unchecked_shr(pmoda, gcdpow)) }; + let minusp2 = unsafe { unchecked_sub(a2, unchecked_shr(addr & a_minus_one, gcdpow)) }; // SAFETY: `a2` is a power-of-two, as proven above. `s2` is strictly less than `a2` // because `(s % a) >> gcdpow` is strictly less than `a >> gcdpow`. return wrapping_mul(minusp2, unsafe { mod_inv(s2, a2) }) & a2minus1; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index c4dc34fff97fa..8a68cdf7d651b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -459,7 +459,7 @@ //! [`Result`] of a collection of each contained value of the original //! [`Result`] values, or [`Err`] if any of the elements was [`Err`]. //! -//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E +//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E-for-Result%3CV%2C%20E%3E //! //! ``` //! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)]; @@ -475,8 +475,8 @@ //! to provide the [`product`][Iterator::product] and //! [`sum`][Iterator::sum] methods. //! -//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E -//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E +//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E-for-Result%3CT%2C%20E%3E +//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E-for-Result%3CT%2C%20E%3E //! //! ``` //! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")]; diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index bf79214f42358..107e71ab68b01 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -85,7 +85,7 @@ use crate::ptr; /// [`NonNull::dangling()`]: ptr::NonNull::dangling #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] +#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] #[must_use] pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. @@ -129,7 +129,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// [`NonNull::dangling()`]: ptr::NonNull::dangling #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")] +#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] #[must_use] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index a66ecc35bbdb1..ebc769ac7ca3b 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -854,6 +854,42 @@ impl AtomicBool { unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } } + /// Logical "not" with a boolean value. + /// + /// Performs a logical "not" operation on the current value, and sets + /// the new value to the result. + /// + /// Returns the previous value. + /// + /// `fetch_not` takes an [`Ordering`] argument which describes the memory ordering + /// of this operation. All ordering modes are possible. Note that using + /// [`Acquire`] makes the store part of this operation [`Relaxed`], and + /// using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note:** This method is only available on platforms that support atomic + /// operations on `u8`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_bool_fetch_not)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let foo = AtomicBool::new(true); + /// assert_eq!(foo.fetch_not(Ordering::SeqCst), true); + /// assert_eq!(foo.load(Ordering::SeqCst), false); + /// + /// let foo = AtomicBool::new(false); + /// assert_eq!(foo.fetch_not(Ordering::SeqCst), false); + /// assert_eq!(foo.load(Ordering::SeqCst), true); + /// ``` + #[inline] + #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")] + #[cfg(target_has_atomic = "8")] + pub fn fetch_not(&self, order: Ordering) -> bool { + self.fetch_xor(true, order) + } + /// Returns a mutable pointer to the underlying [`bool`]. /// /// Doing non-atomic reads and writes on the resulting integer can be a data race. @@ -955,7 +991,7 @@ impl<T> AtomicPtr<T> { /// use std::sync::atomic::AtomicPtr; /// /// let ptr = &mut 5; - /// let atomic_ptr = AtomicPtr::new(ptr); + /// let atomic_ptr = AtomicPtr::new(ptr); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1415,6 +1451,347 @@ impl<T> AtomicPtr<T> { } Err(prev) } + + /// Offsets the pointer's address by adding `val` (in units of `T`), + /// returning the previous pointer. + /// + /// This is equivalent to using [`wrapping_add`] to atomically perform the + /// equivalent of `ptr = ptr.wrapping_add(val);`. + /// + /// This method operates in units of `T`, which means that it cannot be used + /// to offset the pointer by an amount which is not a multiple of + /// `size_of::<T>()`. This can sometimes be inconvenient, as you may want to + /// work with a deliberately misaligned pointer. In such cases, you may use + /// the [`fetch_byte_add`](Self::fetch_byte_add) method instead. + /// + /// `fetch_ptr_add` takes an [`Ordering`] argument which describes the + /// memory ordering of this operation. All ordering modes are possible. Note + /// that using [`Acquire`] makes the store part of this operation + /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// [`wrapping_add`]: pointer::wrapping_add + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); + /// assert_eq!(atom.fetch_ptr_add(1, Ordering::Relaxed).addr(), 0); + /// // Note: units of `size_of::<i64>()`. + /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 8); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { + self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order) + } + + /// Offsets the pointer's address by subtracting `val` (in units of `T`), + /// returning the previous pointer. + /// + /// This is equivalent to using [`wrapping_sub`] to atomically perform the + /// equivalent of `ptr = ptr.wrapping_sub(val);`. + /// + /// This method operates in units of `T`, which means that it cannot be used + /// to offset the pointer by an amount which is not a multiple of + /// `size_of::<T>()`. This can sometimes be inconvenient, as you may want to + /// work with a deliberately misaligned pointer. In such cases, you may use + /// the [`fetch_byte_sub`](Self::fetch_byte_sub) method instead. + /// + /// `fetch_ptr_sub` takes an [`Ordering`] argument which describes the memory + /// ordering of this operation. All ordering modes are possible. Note that + /// using [`Acquire`] makes the store part of this operation [`Relaxed`], + /// and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// [`wrapping_sub`]: pointer::wrapping_sub + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let array = [1i32, 2i32]; + /// let atom = AtomicPtr::new(array.as_ptr().wrapping_add(1) as *mut _); + /// + /// assert!(core::ptr::eq( + /// atom.fetch_ptr_sub(1, Ordering::Relaxed), + /// &array[1], + /// )); + /// assert!(core::ptr::eq(atom.load(Ordering::Relaxed), &array[0])); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { + self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order) + } + + /// Offsets the pointer's address by adding `val` *bytes*, returning the + /// previous pointer. + /// + /// This is equivalent to using [`wrapping_add`] and [`cast`] to atomically + /// perform `ptr = ptr.cast::<u8>().wrapping_add(val).cast::<T>()`. + /// + /// `fetch_byte_add` takes an [`Ordering`] argument which describes the + /// memory ordering of this operation. All ordering modes are possible. Note + /// that using [`Acquire`] makes the store part of this operation + /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// [`wrapping_add`]: pointer::wrapping_add + /// [`cast`]: pointer::cast + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); + /// assert_eq!(atom.fetch_byte_add(1, Ordering::Relaxed).addr(), 0); + /// // Note: in units of bytes, not `size_of::<i64>()`. + /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 1); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() + } + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_add(self.p.get().cast::<usize>(), val, order) as *mut T + } + } + + /// Offsets the pointer's address by subtracting `val` *bytes*, returning the + /// previous pointer. + /// + /// This is equivalent to using [`wrapping_sub`] and [`cast`] to atomically + /// perform `ptr = ptr.cast::<u8>().wrapping_sub(val).cast::<T>()`. + /// + /// `fetch_byte_sub` takes an [`Ordering`] argument which describes the + /// memory ordering of this operation. All ordering modes are possible. Note + /// that using [`Acquire`] makes the store part of this operation + /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// [`wrapping_sub`]: pointer::wrapping_sub + /// [`cast`]: pointer::cast + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let atom = AtomicPtr::<i64>::new(core::ptr::invalid_mut(1)); + /// assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1); + /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 0); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() + } + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_sub(self.p.get().cast::<usize>(), val, order) as *mut T + } + } + + /// Performs a bitwise "or" operation on the address of the current pointer, + /// and the argument `val`, and stores a pointer with provenance of the + /// current pointer and the resulting address. + /// + /// This is equivalent equivalent to using [`map_addr`] to atomically + /// perform `ptr = ptr.map_addr(|a| a | val)`. This can be used in tagged + /// pointer schemes to atomically set tag bits. + /// + /// **Caveat**: This operation returns the previous value. To compute the + /// stored value without losing provenance, you may use [`map_addr`]. For + /// example: `a.fetch_or(val).map_addr(|a| a | val)`. + /// + /// `fetch_or` takes an [`Ordering`] argument which describes the memory + /// ordering of this operation. All ordering modes are possible. Note that + /// using [`Acquire`] makes the store part of this operation [`Relaxed`], + /// and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// This API and its claimed semantics are part of the Strict Provenance + /// experiment, see the [module documentation for `ptr`][crate::ptr] for + /// details. + /// + /// [`map_addr`]: pointer::map_addr + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let pointer = &mut 3i64 as *mut i64; + /// + /// let atom = AtomicPtr::<i64>::new(pointer); + /// // Tag the bottom bit of the pointer. + /// assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 0); + /// // Extract and untag. + /// let tagged = atom.load(Ordering::Relaxed); + /// assert_eq!(tagged.addr() & 1, 1); + /// assert_eq!(tagged.map_addr(|p| p & !1), pointer); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() + } + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_or(self.p.get().cast::<usize>(), val, order) as *mut T + } + } + + /// Performs a bitwise "and" operation on the address of the current + /// pointer, and the argument `val`, and stores a pointer with provenance of + /// the current pointer and the resulting address. + /// + /// This is equivalent equivalent to using [`map_addr`] to atomically + /// perform `ptr = ptr.map_addr(|a| a & val)`. This can be used in tagged + /// pointer schemes to atomically unset tag bits. + /// + /// **Caveat**: This operation returns the previous value. To compute the + /// stored value without losing provenance, you may use [`map_addr`]. For + /// example: `a.fetch_and(val).map_addr(|a| a & val)`. + /// + /// `fetch_and` takes an [`Ordering`] argument which describes the memory + /// ordering of this operation. All ordering modes are possible. Note that + /// using [`Acquire`] makes the store part of this operation [`Relaxed`], + /// and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// This API and its claimed semantics are part of the Strict Provenance + /// experiment, see the [module documentation for `ptr`][crate::ptr] for + /// details. + /// + /// [`map_addr`]: pointer::map_addr + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let pointer = &mut 3i64 as *mut i64; + /// // A tagged pointer + /// let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1)); + /// assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 1); + /// // Untag, and extract the previously tagged pointer. + /// let untagged = atom.fetch_and(!1, Ordering::Relaxed) + /// .map_addr(|a| a & !1); + /// assert_eq!(untagged, pointer); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() + } + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_and(self.p.get().cast::<usize>(), val, order) as *mut T + } + } + + /// Performs a bitwise "xor" operation on the address of the current + /// pointer, and the argument `val`, and stores a pointer with provenance of + /// the current pointer and the resulting address. + /// + /// This is equivalent equivalent to using [`map_addr`] to atomically + /// perform `ptr = ptr.map_addr(|a| a ^ val)`. This can be used in tagged + /// pointer schemes to atomically toggle tag bits. + /// + /// **Caveat**: This operation returns the previous value. To compute the + /// stored value without losing provenance, you may use [`map_addr`]. For + /// example: `a.fetch_xor(val).map_addr(|a| a ^ val)`. + /// + /// `fetch_xor` takes an [`Ordering`] argument which describes the memory + /// ordering of this operation. All ordering modes are possible. Note that + /// using [`Acquire`] makes the store part of this operation [`Relaxed`], + /// and using [`Release`] makes the load part [`Relaxed`]. + /// + /// **Note**: This method is only available on platforms that support atomic + /// operations on [`AtomicPtr`]. + /// + /// This API and its claimed semantics are part of the Strict Provenance + /// experiment, see the [module documentation for `ptr`][crate::ptr] for + /// details. + /// + /// [`map_addr`]: pointer::map_addr + /// + /// # Examples + /// + /// ``` + /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] + /// use core::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let pointer = &mut 3i64 as *mut i64; + /// let atom = AtomicPtr::<i64>::new(pointer); + /// + /// // Toggle a tag bit on the pointer. + /// atom.fetch_xor(1, Ordering::Relaxed); + /// assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1); + /// ``` + #[inline] + #[cfg(target_has_atomic = "ptr")] + #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] + pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() + } + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_xor(self.p.get().cast::<usize>(), val, order) as *mut T + } + } } #[cfg(target_has_atomic_load_store = "8")] @@ -2315,7 +2692,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"), "i8", "", @@ -2335,7 +2712,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"), "u8", "", @@ -2355,7 +2732,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"), "i16", "", @@ -2375,7 +2752,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"), "u16", "", @@ -2395,7 +2772,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"), "i32", "", @@ -2415,7 +2792,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"), "u32", "", @@ -2435,7 +2812,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"), "i64", "", @@ -2455,7 +2832,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"), "u64", "", @@ -2468,14 +2845,14 @@ atomic_int! { atomic_int! { cfg(target_has_atomic = "128"), cfg(target_has_atomic_equal_alignment = "128"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), "i128", "#![feature(integer_atomics)]\n\n", @@ -2488,14 +2865,14 @@ atomic_int! { atomic_int! { cfg(target_has_atomic = "128"), cfg(target_has_atomic_equal_alignment = "128"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), + unstable(feature = "integer_atomics", issue = "99069"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "99069"), cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), "u128", "#![feature(integer_atomics)]\n\n", @@ -2575,11 +2952,11 @@ unsafe fn atomic_store<T: Copy>(dst: *mut T, val: T, order: Ordering) { // SAFETY: the caller must uphold the safety contract for `atomic_store`. unsafe { match order { - Release => intrinsics::atomic_store_rel(dst, val), Relaxed => intrinsics::atomic_store_relaxed(dst, val), - SeqCst => intrinsics::atomic_store(dst, val), + Release => intrinsics::atomic_store_release(dst, val), + SeqCst => intrinsics::atomic_store_seqcst(dst, val), Acquire => panic!("there is no such thing as an acquire store"), - AcqRel => panic!("there is no such thing as an acquire/release store"), + AcqRel => panic!("there is no such thing as an acquire-release store"), } } } @@ -2589,11 +2966,11 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T { // SAFETY: the caller must uphold the safety contract for `atomic_load`. unsafe { match order { - Acquire => intrinsics::atomic_load_acq(dst), Relaxed => intrinsics::atomic_load_relaxed(dst), - SeqCst => intrinsics::atomic_load(dst), + Acquire => intrinsics::atomic_load_acquire(dst), + SeqCst => intrinsics::atomic_load_seqcst(dst), Release => panic!("there is no such thing as a release load"), - AcqRel => panic!("there is no such thing as an acquire/release load"), + AcqRel => panic!("there is no such thing as an acquire-release load"), } } } @@ -2604,11 +2981,11 @@ 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`. unsafe { match order { - Acquire => intrinsics::atomic_xchg_acq(dst, val), - Release => intrinsics::atomic_xchg_rel(dst, val), - AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), - SeqCst => intrinsics::atomic_xchg(dst, val), + Acquire => intrinsics::atomic_xchg_acquire(dst, val), + Release => intrinsics::atomic_xchg_release(dst, val), + AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), + SeqCst => intrinsics::atomic_xchg_seqcst(dst, val), } } } @@ -2620,11 +2997,11 @@ 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`. unsafe { match order { - Acquire => intrinsics::atomic_xadd_acq(dst, val), - Release => intrinsics::atomic_xadd_rel(dst, val), - AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), - SeqCst => intrinsics::atomic_xadd(dst, val), + Acquire => intrinsics::atomic_xadd_acquire(dst, val), + Release => intrinsics::atomic_xadd_release(dst, val), + AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), + SeqCst => intrinsics::atomic_xadd_seqcst(dst, val), } } } @@ -2636,11 +3013,11 @@ 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`. unsafe { match order { - Acquire => intrinsics::atomic_xsub_acq(dst, val), - Release => intrinsics::atomic_xsub_rel(dst, val), - AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), - SeqCst => intrinsics::atomic_xsub(dst, val), + Acquire => intrinsics::atomic_xsub_acquire(dst, val), + Release => intrinsics::atomic_xsub_release(dst, val), + AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), + SeqCst => intrinsics::atomic_xsub_seqcst(dst, val), } } } @@ -2657,16 +3034,22 @@ unsafe fn atomic_compare_exchange<T: Copy>( // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`. let (val, ok) = unsafe { match (success, failure) { - (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), - (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), - (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), + (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new), + //(Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new), + //(Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new), + (Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new), + //(Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new), + //(Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new), + //(Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new), + //(AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new), + (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), } @@ -2686,16 +3069,22 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>( // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange_weak`. let (val, ok) = unsafe { match (success, failure) { - (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acq(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchgweak_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), - (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), - (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), + (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed_relaxed(dst, old, new), + //(Relaxed, Acquire) => intrinsics::atomic_cxchgweak_relaxed_acquire(dst, old, new), + //(Relaxed, SeqCst) => intrinsics::atomic_cxchgweak_relaxed_seqcst(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acquire_relaxed(dst, old, new), + (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acquire_acquire(dst, old, new), + //(Acquire, SeqCst) => intrinsics::atomic_cxchgweak_acquire_seqcst(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchgweak_release_relaxed(dst, old, new), + //(Release, Acquire) => intrinsics::atomic_cxchgweak_release_acquire(dst, old, new), + //(Release, SeqCst) => intrinsics::atomic_cxchgweak_release_seqcst(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_relaxed(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel_acquire(dst, old, new), + //(AcqRel, SeqCst) => intrinsics::atomic_cxchgweak_acqrel_seqcst(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_seqcst_relaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_seqcst_acquire(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak_seqcst_seqcst(dst, old, new), + (_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), } @@ -2709,11 +3098,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_and_acq(dst, val), - Release => intrinsics::atomic_and_rel(dst, val), - AcqRel => intrinsics::atomic_and_acqrel(dst, val), Relaxed => intrinsics::atomic_and_relaxed(dst, val), - SeqCst => intrinsics::atomic_and(dst, val), + Acquire => intrinsics::atomic_and_acquire(dst, val), + Release => intrinsics::atomic_and_release(dst, val), + AcqRel => intrinsics::atomic_and_acqrel(dst, val), + SeqCst => intrinsics::atomic_and_seqcst(dst, val), } } } @@ -2724,11 +3113,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_nand_acq(dst, val), - Release => intrinsics::atomic_nand_rel(dst, val), - AcqRel => intrinsics::atomic_nand_acqrel(dst, val), Relaxed => intrinsics::atomic_nand_relaxed(dst, val), - SeqCst => intrinsics::atomic_nand(dst, val), + Acquire => intrinsics::atomic_nand_acquire(dst, val), + Release => intrinsics::atomic_nand_release(dst, val), + AcqRel => intrinsics::atomic_nand_acqrel(dst, val), + SeqCst => intrinsics::atomic_nand_seqcst(dst, val), } } } @@ -2739,11 +3128,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_or_acq(dst, val), - Release => intrinsics::atomic_or_rel(dst, val), + SeqCst => intrinsics::atomic_or_seqcst(dst, val), + Acquire => intrinsics::atomic_or_acquire(dst, val), + Release => intrinsics::atomic_or_release(dst, val), AcqRel => intrinsics::atomic_or_acqrel(dst, val), Relaxed => intrinsics::atomic_or_relaxed(dst, val), - SeqCst => intrinsics::atomic_or(dst, val), } } } @@ -2754,11 +3143,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_xor_acq(dst, val), - Release => intrinsics::atomic_xor_rel(dst, val), + SeqCst => intrinsics::atomic_xor_seqcst(dst, val), + Acquire => intrinsics::atomic_xor_acquire(dst, val), + Release => intrinsics::atomic_xor_release(dst, val), AcqRel => intrinsics::atomic_xor_acqrel(dst, val), Relaxed => intrinsics::atomic_xor_relaxed(dst, val), - SeqCst => intrinsics::atomic_xor(dst, val), } } } @@ -2770,11 +3159,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_max_acq(dst, val), - Release => intrinsics::atomic_max_rel(dst, val), - AcqRel => intrinsics::atomic_max_acqrel(dst, val), Relaxed => intrinsics::atomic_max_relaxed(dst, val), - SeqCst => intrinsics::atomic_max(dst, val), + Acquire => intrinsics::atomic_max_acquire(dst, val), + Release => intrinsics::atomic_max_release(dst, val), + AcqRel => intrinsics::atomic_max_acqrel(dst, val), + SeqCst => intrinsics::atomic_max_seqcst(dst, val), } } } @@ -2786,11 +3175,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_min_acq(dst, val), - Release => intrinsics::atomic_min_rel(dst, val), - AcqRel => intrinsics::atomic_min_acqrel(dst, val), Relaxed => intrinsics::atomic_min_relaxed(dst, val), - SeqCst => intrinsics::atomic_min(dst, val), + Acquire => intrinsics::atomic_min_acquire(dst, val), + Release => intrinsics::atomic_min_release(dst, val), + AcqRel => intrinsics::atomic_min_acqrel(dst, val), + SeqCst => intrinsics::atomic_min_seqcst(dst, val), } } } @@ -2802,11 +3191,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_umax_acq(dst, val), - Release => intrinsics::atomic_umax_rel(dst, val), - AcqRel => intrinsics::atomic_umax_acqrel(dst, val), Relaxed => intrinsics::atomic_umax_relaxed(dst, val), - SeqCst => intrinsics::atomic_umax(dst, val), + Acquire => intrinsics::atomic_umax_acquire(dst, val), + Release => intrinsics::atomic_umax_release(dst, val), + AcqRel => intrinsics::atomic_umax_acqrel(dst, val), + SeqCst => intrinsics::atomic_umax_seqcst(dst, val), } } } @@ -2818,11 +3207,11 @@ 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` unsafe { match order { - Acquire => intrinsics::atomic_umin_acq(dst, val), - Release => intrinsics::atomic_umin_rel(dst, val), - AcqRel => intrinsics::atomic_umin_acqrel(dst, val), Relaxed => intrinsics::atomic_umin_relaxed(dst, val), - SeqCst => intrinsics::atomic_umin(dst, val), + Acquire => intrinsics::atomic_umin_acquire(dst, val), + Release => intrinsics::atomic_umin_release(dst, val), + AcqRel => intrinsics::atomic_umin_acqrel(dst, val), + SeqCst => intrinsics::atomic_umin_seqcst(dst, val), } } } @@ -2908,10 +3297,10 @@ pub fn fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { match order { - Acquire => intrinsics::atomic_fence_acq(), - Release => intrinsics::atomic_fence_rel(), + Acquire => intrinsics::atomic_fence_acquire(), + Release => intrinsics::atomic_fence_release(), AcqRel => intrinsics::atomic_fence_acqrel(), - SeqCst => intrinsics::atomic_fence(), + SeqCst => intrinsics::atomic_fence_seqcst(), Relaxed => panic!("there is no such thing as a relaxed fence"), } } @@ -2990,10 +3379,10 @@ pub fn compiler_fence(order: Ordering) { // SAFETY: using an atomic fence is safe. unsafe { match order { - Acquire => intrinsics::atomic_singlethreadfence_acq(), - Release => intrinsics::atomic_singlethreadfence_rel(), + Acquire => intrinsics::atomic_singlethreadfence_acquire(), + Release => intrinsics::atomic_singlethreadfence_release(), AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), - SeqCst => intrinsics::atomic_singlethreadfence(), + SeqCst => intrinsics::atomic_singlethreadfence_seqcst(), Relaxed => panic!("there is no such thing as a relaxed compiler fence"), } } diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs new file mode 100644 index 0000000000000..a7519ab5ab633 --- /dev/null +++ b/library/core/src/sync/exclusive.rs @@ -0,0 +1,173 @@ +//! Defines [`Exclusive`]. + +use core::fmt; +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_ +/// access to the underlying value. It provides no _immutable_, or _shared_ +/// access to the underlying value. +/// +/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_ +/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive` +/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound +/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API +/// whatsoever, making it useless, thus harmless, thus memory safe. +/// +/// Certain constructs like [`Future`]s can only be used with _exclusive_ access, +/// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the +/// rust compiler that something is `Sync` in practice. +/// +/// ## Examples +/// Using a non-`Sync` future prevents the wrapping struct from being `Sync` +/// ```compile_fail +/// use core::cell::Cell; +/// +/// async fn other() {} +/// fn assert_sync<T: Sync>(t: T) {} +/// struct State<F> { +/// future: F +/// } +/// +/// assert_sync(State { +/// future: async { +/// let cell = Cell::new(1); +/// let cell_ref = &cell; +/// other().await; +/// let value = cell_ref.get(); +/// } +/// }); +/// ``` +/// +/// `Exclusive` ensures the struct is `Sync` without stripping the future of its +/// functionality. +/// ``` +/// #![feature(exclusive_wrapper)] +/// use core::cell::Cell; +/// use core::sync::Exclusive; +/// +/// async fn other() {} +/// fn assert_sync<T: Sync>(t: T) {} +/// struct State<F> { +/// future: Exclusive<F> +/// } +/// +/// assert_sync(State { +/// future: Exclusive::new(async { +/// let cell = Cell::new(1); +/// let cell_ref = &cell; +/// other().await; +/// let value = cell_ref.get(); +/// }) +/// }); +/// ``` +/// +/// ## Parallels with a mutex +/// In some sense, `Exclusive` can be thought of as a _compile-time_ version of +/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist +/// for any value. This is a parallel with the fact that +/// `&` and `&mut` references together can be thought of as a _compile-time_ +/// version of a read-write lock. +/// +/// +/// [`Sync`]: core::marker::Sync +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[doc(alias = "SyncWrapper")] +#[doc(alias = "SyncCell")] +#[doc(alias = "Unique")] +// `Exclusive` can't have `PartialOrd`, `Clone`, etc. impls as they would +// use `&` access to the inner value, violating the `Sync` impl's safety +// requirements. +#[derive(Default)] +#[repr(transparent)] +pub struct Exclusive<T: ?Sized> { + inner: T, +} + +// See `Exclusive`'s docs for justification. +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +unsafe impl<T: ?Sized> Sync for Exclusive<T> {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl<T: ?Sized> fmt::Debug for Exclusive<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_struct("Exclusive").finish_non_exhaustive() + } +} + +impl<T: Sized> Exclusive<T> { + /// Wrap a value in an `Exclusive` + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + pub const fn new(t: T) -> Self { + Self { inner: t } + } + + /// Unwrap the value contained in the `Exclusive` + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + pub const fn into_inner(self) -> T { + self.inner + } +} + +impl<T: ?Sized> Exclusive<T> { + /// Get exclusive access to the underlying value. + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + pub const fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + /// Get pinned exclusive access to the underlying value. + /// + /// `Exclusive` is considered to _structurally pin_ the underlying + /// value, which means _unpinned_ `Exclusive`s can produce _unpinned_ + /// access to the underlying value, but _pinned_ `Exclusive`s only + /// produce _pinned_ access to the underlying value. + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { + // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned + // `Pin::map_unchecked_mut` is not const, so we do this conversion manually + unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } + } + + /// Build a _mutable_ references to an `Exclusive<T>` from + /// a _mutable_ reference to a `T`. This allows you to skip + /// building an `Exclusive` with [`Exclusive::new`]. + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> { + // SAFETY: repr is ≥ C, so refs have the same layout; and `Exclusive` properties are `&mut`-agnostic + unsafe { &mut *(r as *mut T as *mut Exclusive<T>) } + } + + /// Build a _pinned mutable_ references to an `Exclusive<T>` from + /// a _pinned mutable_ reference to a `T`. This allows you to skip + /// building an `Exclusive` with [`Exclusive::new`]. + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> { + // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned + // `Pin::map_unchecked_mut` is not const, so we do this conversion manually + unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) } + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl<T> From<T> for Exclusive<T> { + fn from(t: T) -> Self { + Self::new(t) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl<T: Future + ?Sized> Future for Exclusive<T> { + type Output = T::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + self.get_pin_mut().poll(cx) + } +} diff --git a/library/core/src/sync/mod.rs b/library/core/src/sync/mod.rs index b635bae0a47b4..4365e4cb250ca 100644 --- a/library/core/src/sync/mod.rs +++ b/library/core/src/sync/mod.rs @@ -3,3 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] pub mod atomic; +mod exclusive; +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +pub use exclusive::Exclusive; diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index ab3763cbc4196..b664b0bb866db 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -107,7 +107,7 @@ macro_rules! tuple_impls { // Otherwise, it hides the docs entirely. macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[cfg_attr(not(bootstrap), doc(tuple_variadic))] + #[doc(tuple_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs index 6762c0319e5cf..8a5a06b3440f8 100644 --- a/library/core/tests/alloc.rs +++ b/library/core/tests/alloc.rs @@ -1,5 +1,5 @@ use core::alloc::Layout; -use core::ptr::NonNull; +use core::ptr::{self, NonNull}; #[test] fn const_unchecked_layout() { @@ -9,7 +9,7 @@ fn const_unchecked_layout() { const DANGLING: NonNull<u8> = LAYOUT.dangling(); assert_eq!(LAYOUT.size(), SIZE); assert_eq!(LAYOUT.align(), ALIGN); - assert_eq!(Some(DANGLING), NonNull::new(ALIGN as *mut u8)); + assert_eq!(Some(DANGLING), NonNull::new(ptr::invalid_mut(ALIGN))); } #[test] diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 7f8672f035417..13b12db209a76 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -127,6 +127,91 @@ fn int_max() { assert_eq!(x.load(SeqCst), 0xf731); } +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_add_null() { + let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); + assert_eq!(atom.fetch_ptr_add(1, SeqCst).addr(), 0); + assert_eq!(atom.load(SeqCst).addr(), 8); + + assert_eq!(atom.fetch_byte_add(1, SeqCst).addr(), 8); + assert_eq!(atom.load(SeqCst).addr(), 9); + + assert_eq!(atom.fetch_ptr_sub(1, SeqCst).addr(), 9); + assert_eq!(atom.load(SeqCst).addr(), 1); + + assert_eq!(atom.fetch_byte_sub(1, SeqCst).addr(), 1); + assert_eq!(atom.load(SeqCst).addr(), 0); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_add_data() { + let num = 0i64; + let n = &num as *const i64 as *mut _; + let atom = AtomicPtr::<i64>::new(n); + assert_eq!(atom.fetch_ptr_add(1, SeqCst), n); + assert_eq!(atom.load(SeqCst), n.wrapping_add(1)); + + assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1)); + assert_eq!(atom.load(SeqCst), n); + let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>(); + + assert_eq!(atom.fetch_byte_add(1, SeqCst), n); + assert_eq!(atom.load(SeqCst), bytes_from_n(1)); + + assert_eq!(atom.fetch_byte_add(5, SeqCst), bytes_from_n(1)); + assert_eq!(atom.load(SeqCst), bytes_from_n(6)); + + assert_eq!(atom.fetch_byte_sub(1, SeqCst), bytes_from_n(6)); + assert_eq!(atom.load(SeqCst), bytes_from_n(5)); + + assert_eq!(atom.fetch_byte_sub(5, SeqCst), bytes_from_n(5)); + assert_eq!(atom.load(SeqCst), n); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_bitops() { + let atom = AtomicPtr::<i64>::new(core::ptr::null_mut()); + assert_eq!(atom.fetch_or(0b0111, SeqCst).addr(), 0); + assert_eq!(atom.load(SeqCst).addr(), 0b0111); + + assert_eq!(atom.fetch_and(0b1101, SeqCst).addr(), 0b0111); + assert_eq!(atom.load(SeqCst).addr(), 0b0101); + + assert_eq!(atom.fetch_xor(0b1111, SeqCst).addr(), 0b0101); + assert_eq!(atom.load(SeqCst).addr(), 0b1010); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_bitops_tagging() { + #[repr(align(16))] + struct Tagme(u128); + + let tagme = Tagme(1000); + let ptr = &tagme as *const Tagme as *mut Tagme; + let atom: AtomicPtr<Tagme> = AtomicPtr::new(ptr); + + const MASK_TAG: usize = 0b1111; + const MASK_PTR: usize = !MASK_TAG; + + assert_eq!(ptr.addr() & MASK_TAG, 0); + + assert_eq!(atom.fetch_or(0b0111, SeqCst), ptr); + assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b111)); + + assert_eq!(atom.fetch_and(MASK_PTR | 0b0010, SeqCst), ptr.map_addr(|a| a | 0b111)); + assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b0010)); + + assert_eq!(atom.fetch_xor(0b1011, SeqCst), ptr.map_addr(|a| a | 0b0010)); + assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b1001)); + + assert_eq!(atom.fetch_and(MASK_PTR, SeqCst), ptr.map_addr(|a| a | 0b1001)); + assert_eq!(atom.load(SeqCst), ptr); +} + static S_FALSE: AtomicBool = AtomicBool::new(false); static S_TRUE: AtomicBool = AtomicBool::new(true); static S_INT: AtomicIsize = AtomicIsize::new(0); diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs index 5bc6aac1778f5..f7934d062a379 100644 --- a/library/core/tests/hash/mod.rs +++ b/library/core/tests/hash/mod.rs @@ -2,6 +2,7 @@ mod sip; use std::default::Default; use std::hash::{BuildHasher, Hash, Hasher}; +use std::ptr; use std::rc::Rc; struct MyHasher { @@ -69,10 +70,10 @@ fn test_writer_hasher() { let cs: Rc<[u8]> = Rc::new([1, 2, 3]); assert_eq!(hash(&cs), 9); - let ptr = 5_usize as *const i32; + let ptr = ptr::invalid::<i32>(5_usize); assert_eq!(hash(&ptr), 5); - let ptr = 5_usize as *mut i32; + let ptr = ptr::invalid_mut::<i32>(5_usize); assert_eq!(hash(&ptr), 5); if cfg!(miri) { diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index 731b1592d4193..37345c1d38142 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -575,6 +575,15 @@ fn iter_try_collect_uses_try_fold_not_next() { // validation is just that it didn't panic. } +#[test] +fn test_next_chunk() { + let mut it = 0..12; + assert_eq!(it.next_chunk().unwrap(), [0, 1, 2, 3]); + assert_eq!(it.next_chunk().unwrap(), []); + assert_eq!(it.next_chunk().unwrap(), [4, 5, 6, 7, 8, 9]); + assert_eq!(it.next_chunk::<4>().unwrap_err().as_slice(), &[10, 11]); +} + // just tests by whether or not this compiles fn _empty_impl_all_auto_traits<T>() { use std::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 63c9602abe75c..db94368f6e0cc 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -19,7 +19,6 @@ #![feature(const_ptr_write)] #![feature(const_trait_impl)] #![feature(const_likely)] -#![feature(core_ffi_c)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -33,7 +32,6 @@ #![feature(fmt_internals)] #![feature(float_minimum_maximum)] #![feature(future_join)] -#![feature(future_poll_fn)] #![feature(generic_assert_internals)] #![feature(array_try_from_fn)] #![feature(hasher_prefixfree_extras)] @@ -67,12 +65,12 @@ #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] +#![feature(iter_next_chunk)] #![feature(iter_order_by)] #![feature(iterator_try_collect)] #![feature(iterator_try_reduce)] #![feature(const_mut_refs)] #![feature(const_pin)] -#![feature(const_slice_from_raw_parts)] #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(result_into_ok_or_err)] @@ -89,6 +87,7 @@ #![feature(slice_group_by)] #![feature(split_array)] #![feature(strict_provenance)] +#![feature(strict_provenance_atomic_ptr)] #![feature(trusted_random_access)] #![feature(unsize)] #![feature(unzip_option)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 3e2956eac8753..12861794c2d2c 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -96,17 +96,14 @@ fn test_is_null() { let nmi: *mut dyn ToString = null_mut::<isize>(); assert!(nmi.is_null()); - #[cfg(not(bootstrap))] - { - extern "C" { - type Extern; - } - let ec: *const Extern = null::<Extern>(); - assert!(ec.is_null()); - - let em: *mut Extern = null_mut::<Extern>(); - assert!(em.is_null()); + extern "C" { + type Extern; } + let ec: *const Extern = null::<Extern>(); + assert!(ec.is_null()); + + let em: *mut Extern = null_mut::<Extern>(); + assert!(em.is_null()); } #[test] @@ -353,16 +350,16 @@ fn align_offset_zst() { // all, because no amount of elements will align the pointer. let mut p = 1; while p < 1024 { - assert_eq!((p as *const ()).align_offset(p), 0); + assert_eq!(ptr::invalid::<()>(p).align_offset(p), 0); if p != 1 { - assert_eq!(((p + 1) as *const ()).align_offset(p), !0); + assert_eq!(ptr::invalid::<()>(p + 1).align_offset(p), !0); } p = (p + 1).next_power_of_two(); } } #[test] -fn align_offset_stride1() { +fn align_offset_stride_one() { // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to // number of bytes. let mut align = 1; @@ -371,7 +368,7 @@ fn align_offset_stride1() { let expected = ptr % align; let offset = if expected == 0 { 0 } else { align - expected }; assert_eq!( - (ptr as *const u8).align_offset(align), + ptr::invalid::<u8>(ptr).align_offset(align), offset, "ptr = {}, align = {}, size = 1", ptr, @@ -383,24 +380,8 @@ fn align_offset_stride1() { } #[test] -fn align_offset_weird_strides() { - #[repr(packed)] - struct A3(u16, u8); - struct A4(u32); - #[repr(packed)] - struct A5(u32, u8); - #[repr(packed)] - struct A6(u32, u16); - #[repr(packed)] - struct A7(u32, u16, u8); - #[repr(packed)] - struct A8(u32, u32); - #[repr(packed)] - struct A9(u32, u32, u8); - #[repr(packed)] - struct A10(u32, u32, u16); - - unsafe fn test_weird_stride<T>(ptr: *const T, align: usize) -> bool { +fn align_offset_various_strides() { + unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool { let numptr = ptr as usize; let mut expected = usize::MAX; // Naive but definitely correct way to find the *first* aligned element of stride::<T>. @@ -434,14 +415,39 @@ fn align_offset_weird_strides() { while align < limit { for ptr in 1usize..4 * align { unsafe { - x |= test_weird_stride::<A3>(ptr as *const A3, align); - x |= test_weird_stride::<A4>(ptr as *const A4, align); - x |= test_weird_stride::<A5>(ptr as *const A5, align); - x |= test_weird_stride::<A6>(ptr as *const A6, align); - x |= test_weird_stride::<A7>(ptr as *const A7, align); - x |= test_weird_stride::<A8>(ptr as *const A8, align); - x |= test_weird_stride::<A9>(ptr as *const A9, align); - x |= test_weird_stride::<A10>(ptr as *const A10, align); + #[repr(packed)] + struct A3(u16, u8); + x |= test_stride::<A3>(ptr::invalid::<A3>(ptr), align); + + struct A4(u32); + x |= test_stride::<A4>(ptr::invalid::<A4>(ptr), align); + + #[repr(packed)] + struct A5(u32, u8); + x |= test_stride::<A5>(ptr::invalid::<A5>(ptr), align); + + #[repr(packed)] + struct A6(u32, u16); + x |= test_stride::<A6>(ptr::invalid::<A6>(ptr), align); + + #[repr(packed)] + struct A7(u32, u16, u8); + x |= test_stride::<A7>(ptr::invalid::<A7>(ptr), align); + + #[repr(packed)] + struct A8(u32, u32); + x |= test_stride::<A8>(ptr::invalid::<A8>(ptr), align); + + #[repr(packed)] + struct A9(u32, u32, u8); + x |= test_stride::<A9>(ptr::invalid::<A9>(ptr), align); + + #[repr(packed)] + struct A10(u32, u32, u16); + x |= test_stride::<A10>(ptr::invalid::<A10>(ptr), align); + + x |= test_stride::<u32>(ptr::invalid::<u32>(ptr), align); + x |= test_stride::<u128>(ptr::invalid::<u128>(ptr), align); } } align = (align + 1).next_power_of_two(); @@ -479,8 +485,8 @@ fn ptr_metadata() { let () = metadata(&[4, 7]); let () = metadata(&(4, String::new())); let () = metadata(&Pair(4, String::new())); - let () = metadata(0 as *const Extern); - let () = metadata(0 as *const <&u32 as std::ops::Deref>::Target); + let () = metadata(ptr::null::<()>() as *const Extern); + let () = metadata(ptr::null::<()>() as *const <&u32 as std::ops::Deref>::Target); assert_eq!(metadata("foo"), 3_usize); assert_eq!(metadata(&[4, 7][..]), 2_usize); @@ -784,6 +790,31 @@ fn nonnull_tagged_pointer_with_provenance() { } } +#[test] +fn swap_copy_untyped() { + // We call `{swap,copy}{,_nonoverlapping}` at `bool` type on data that is not a valid bool. + // These should all do untyped copies, so this should work fine. + let mut x = 5u8; + let mut y = 6u8; + + let ptr1 = &mut x as *mut u8 as *mut bool; + let ptr2 = &mut y as *mut u8 as *mut bool; + + unsafe { + ptr::swap(ptr1, ptr2); + ptr::swap_nonoverlapping(ptr1, ptr2, 1); + } + assert_eq!(x, 5); + assert_eq!(y, 6); + + unsafe { + ptr::copy(ptr1, ptr2, 1); + ptr::copy_nonoverlapping(ptr1, ptr2, 1); + } + assert_eq!(x, 5); + assert_eq!(y, 5); +} + #[test] fn test_const_copy() { const { diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs index c28ea859115e1..bbace0ef66ca3 100644 --- a/library/core/tests/unicode.rs +++ b/library/core/tests/unicode.rs @@ -1,5 +1,5 @@ #[test] pub fn version() { - let (major, _minor, _update) = core::unicode::UNICODE_VERSION; + let (major, _minor, _update) = core::char::UNICODE_VERSION; assert!(major >= 10); } diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs index 6602ab36ba714..38a3a0adad98e 100644 --- a/library/core/tests/waker.rs +++ b/library/core/tests/waker.rs @@ -3,7 +3,7 @@ use std::task::{RawWaker, RawWakerVTable, Waker}; #[test] fn test_waker_getters() { - let raw_waker = RawWaker::new(42usize as *mut (), &WAKER_VTABLE); + let raw_waker = RawWaker::new(ptr::invalid_mut(42usize), &WAKER_VTABLE); assert_eq!(raw_waker.data() as usize, 42); assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE)); @@ -15,7 +15,7 @@ fn test_waker_getters() { } static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( - |data| RawWaker::new((data as usize + 1) as *mut (), &WAKER_VTABLE), + |data| RawWaker::new(ptr::invalid_mut(data as usize + 1), &WAKER_VTABLE), |_| {}, |_| {}, |_| {}, diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index d7cc700495b97..8254bd6e5024a 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -175,14 +175,12 @@ define_handles! { 'owned: FreeFunctions, TokenStream, - Group, Literal, SourceFile, MultiSpan, Diagnostic, 'interned: - Punct, Ident, Span, } @@ -199,12 +197,6 @@ impl Clone for TokenStream { } } -impl Clone for Group { - fn clone(&self) -> Self { - self.clone() - } -} - impl Clone for Literal { fn clone(&self) -> Self { self.clone() @@ -230,6 +222,20 @@ impl Clone for SourceFile { } } +impl Span { + pub(crate) fn def_site() -> Span { + Bridge::with(|bridge| bridge.globals.def_site) + } + + pub(crate) fn call_site() -> Span { + Bridge::with(|bridge| bridge.globals.call_site) + } + + pub(crate) fn mixed_site() -> Span { + Bridge::with(|bridge| bridge.globals.mixed_site) + } +} + impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.debug()) @@ -263,6 +269,21 @@ macro_rules! define_client_side { } with_api!(self, self, define_client_side); +struct Bridge<'a> { + /// Reusable buffer (only `clear`-ed, never shrunk), primarily + /// used for making requests. + cached_buffer: Buffer, + + /// Server-side function that the client uses to make requests. + dispatch: closure::Closure<'a, Buffer, Buffer>, + + /// Provided globals for this macro expansion. + globals: ExpnGlobals<Span>, +} + +impl<'a> !Send for Bridge<'a> {} +impl<'a> !Sync for Bridge<'a> {} + enum BridgeState<'a> { /// No server is currently connected to this client. NotConnected, @@ -305,34 +326,6 @@ impl BridgeState<'_> { } impl Bridge<'_> { - pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) - } - - fn enter<R>(self, f: impl FnOnce() -> R) -> R { - let force_show_panics = self.force_show_panics; - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); - - BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f)) - } - fn with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { BridgeState::with(|state| match state { BridgeState::NotConnected => { @@ -346,6 +339,13 @@ impl Bridge<'_> { } } +pub(crate) fn is_available() -> bool { + BridgeState::with(|state| match state { + BridgeState::Connected(_) | BridgeState::InUse => true, + BridgeState::NotConnected => false, + }) +} + /// A client-side RPC entry-point, which may be using a different `proc_macro` /// from the one used by the server, but can be invoked compatibly. /// @@ -363,7 +363,7 @@ pub struct Client<I, O> { // a wrapper `fn` pointer, once `const fn` can reference `static`s. pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - pub(super) run: extern "C" fn(Bridge<'_>) -> Buffer, + pub(super) run: extern "C" fn(BridgeConfig<'_>) -> Buffer, pub(super) _marker: PhantomData<fn(I) -> O>, } @@ -375,40 +375,62 @@ impl<I, O> Clone for Client<I, O> { } } +fn maybe_install_panic_hook(force_show_panics: bool) { + // Hide the default panic output within `proc_macro` expansions. + // NB. the server can't do this because it may use a different libstd. + static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); + HIDE_PANICS_DURING_EXPANSION.call_once(|| { + let prev = panic::take_hook(); + panic::set_hook(Box::new(move |info| { + let show = BridgeState::with(|state| match state { + BridgeState::NotConnected => true, + BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, + }); + if show { + prev(info) + } + })); + }); +} + /// Client-side helper for handling client panics, entering the bridge, /// deserializing input and serializing output. // FIXME(eddyb) maybe replace `Bridge::enter` with this? fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( - mut bridge: Bridge<'_>, + config: BridgeConfig<'_>, f: impl FnOnce(A) -> R, ) -> Buffer { - // The initial `cached_buffer` contains the input. - let mut buf = bridge.cached_buffer.take(); + let BridgeConfig { input: mut buf, dispatch, force_show_panics, .. } = config; panic::catch_unwind(panic::AssertUnwindSafe(|| { - bridge.enter(|| { - let reader = &mut &buf[..]; - let input = A::decode(reader, &mut ()); - - // Put the `cached_buffer` back in the `Bridge`, for requests. - Bridge::with(|bridge| bridge.cached_buffer = buf.take()); - - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); + maybe_install_panic_hook(force_show_panics); + + let reader = &mut &buf[..]; + let (globals, input) = <(ExpnGlobals<Span>, A)>::decode(reader, &mut ()); + + // Put the buffer we used for input back in the `Bridge` for requests. + let new_state = + BridgeState::Connected(Bridge { cached_buffer: buf.take(), dispatch, globals }); + + BRIDGE_STATE.with(|state| { + state.set(new_state, || { + let output = f(input); + + // Take the `cached_buffer` back out, for the output value. + buf = Bridge::with(|bridge| bridge.cached_buffer.take()); + + // HACK(eddyb) Separate encoding a success value (`Ok(output)`) + // from encoding a panic (`Err(e: PanicMessage)`) to avoid + // having handles outside the `bridge.enter(|| ...)` scope, and + // to catch panics that could happen while encoding the success. + // + // Note that panics should be impossible beyond this point, but + // this is defensively trying to avoid any accidental panicking + // reaching the `extern "C"` (which should `abort` but might not + // at the moment, so this is also potentially preventing UB). + buf.clear(); + Ok::<_, ()>(output).encode(&mut buf, &mut ()); + }) }) })) .map_err(PanicMessage::from) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 4e931569ef633..048ba3a8fdb79 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -65,11 +65,11 @@ macro_rules! with_api { fn from_str(src: &str) -> $S::TokenStream; fn to_string($self: &$S::TokenStream) -> String; fn from_token_tree( - tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>, + tree: TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>, ) -> $S::TokenStream; fn concat_trees( base: Option<$S::TokenStream>, - trees: Vec<TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>>, + trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>>, ) -> $S::TokenStream; fn concat_streams( base: Option<$S::TokenStream>, @@ -77,25 +77,7 @@ macro_rules! with_api { ) -> $S::TokenStream; fn into_trees( $self: $S::TokenStream - ) -> Vec<TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>>; - }, - Group { - fn drop($self: $S::Group); - fn clone($self: &$S::Group) -> $S::Group; - fn new(delimiter: Delimiter, stream: Option<$S::TokenStream>) -> $S::Group; - fn delimiter($self: &$S::Group) -> Delimiter; - fn stream($self: &$S::Group) -> $S::TokenStream; - fn span($self: &$S::Group) -> $S::Span; - fn span_open($self: &$S::Group) -> $S::Span; - fn span_close($self: &$S::Group) -> $S::Span; - fn set_span($self: &mut $S::Group, span: $S::Span); - }, - Punct { - fn new(ch: char, spacing: Spacing) -> $S::Punct; - fn as_char($self: $S::Punct) -> char; - fn spacing($self: $S::Punct) -> Spacing; - fn span($self: $S::Punct) -> $S::Span; - fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct; + ) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Ident, $S::Literal>>; }, Ident { fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; @@ -151,9 +133,6 @@ macro_rules! with_api { }, Span { fn debug($self: $S::Span) -> String; - fn def_site() -> $S::Span; - fn call_site() -> $S::Span; - fn mixed_site() -> $S::Span; fn source_file($self: $S::Span) -> $S::SourceFile; fn parent($self: $S::Span) -> Option<$S::Span>; fn source($self: $S::Span) -> $S::Span; @@ -213,16 +192,15 @@ use buffer::Buffer; pub use rpc::PanicMessage; use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; -/// An active connection between a server and a client. -/// The server creates the bridge (`Bridge::run_server` in `server.rs`), -/// then passes it to the client through the function pointer in the `run` -/// field of `client::Client`. The client holds its copy of the `Bridge` +/// Configuration for establishing an active connection between a server and a +/// client. The server creates the bridge config (`run_server` in `server.rs`), +/// then passes it to the client through the function pointer in the `run` field +/// of `client::Client`. The client constructs a local `Bridge` from the config /// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). #[repr(C)] -pub struct Bridge<'a> { - /// Reusable buffer (only `clear`-ed, never shrunk), primarily - /// used for making requests, but also for passing input to client. - cached_buffer: Buffer, +pub struct BridgeConfig<'a> { + /// Buffer used to pass initial input to the client. + input: Buffer, /// Server-side function that the client uses to make requests. dispatch: closure::Closure<'a, Buffer, Buffer>, @@ -347,6 +325,7 @@ mark_noop! { &'_ [u8], &'_ str, String, + u8, usize, Delimiter, Level, @@ -379,6 +358,25 @@ rpc_encode_decode!( ); macro_rules! mark_compound { + (struct $name:ident <$($T:ident),+> { $($field:ident),* $(,)? }) => { + impl<$($T: Mark),+> Mark for $name <$($T),+> { + type Unmarked = $name <$($T::Unmarked),+>; + fn mark(unmarked: Self::Unmarked) -> Self { + $name { + $($field: Mark::mark(unmarked.$field)),* + } + } + } + + impl<$($T: Unmark),+> Unmark for $name <$($T),+> { + type Unmarked = $name <$($T::Unmarked),+>; + fn unmark(self) -> Self::Unmarked { + $name { + $($field: Unmark::unmark(self.$field)),* + } + } + } + }; (enum $name:ident <$($T:ident),+> { $($variant:ident $(($field:ident))?),* $(,)? }) => { impl<$($T: Mark),+> Mark for $name <$($T),+> { type Unmarked = $name <$($T::Unmarked),+>; @@ -433,19 +431,65 @@ compound_traits!( } ); +#[derive(Copy, Clone)] +pub struct DelimSpan<Span> { + pub open: Span, + pub close: Span, + pub entire: Span, +} + +impl<Span: Copy> DelimSpan<Span> { + pub fn from_single(span: Span) -> Self { + DelimSpan { open: span, close: span, entire: span } + } +} + +compound_traits!(struct DelimSpan<Span> { open, close, entire }); + +#[derive(Clone)] +pub struct Group<TokenStream, Span> { + pub delimiter: Delimiter, + pub stream: Option<TokenStream>, + pub span: DelimSpan<Span>, +} + +compound_traits!(struct Group<TokenStream, Span> { delimiter, stream, span }); + +#[derive(Clone)] +pub struct Punct<Span> { + pub ch: u8, + pub joint: bool, + pub span: Span, +} + +compound_traits!(struct Punct<Span> { ch, joint, span }); + #[derive(Clone)] -pub enum TokenTree<G, P, I, L> { - Group(G), - Punct(P), - Ident(I), - Literal(L), +pub enum TokenTree<TokenStream, Span, Ident, Literal> { + Group(Group<TokenStream, Span>), + Punct(Punct<Span>), + Ident(Ident), + Literal(Literal), } compound_traits!( - enum TokenTree<G, P, I, L> { + enum TokenTree<TokenStream, Span, Ident, Literal> { Group(tt), Punct(tt), Ident(tt), Literal(tt), } ); + +/// Globals provided alongside the initial inputs for a macro expansion. +/// Provides values such as spans which are used frequently to avoid RPC. +#[derive(Clone)] +pub struct ExpnGlobals<Span> { + pub def_site: Span, + pub call_site: Span, + pub mixed_site: Span, +} + +compound_traits!( + struct ExpnGlobals<Span> { def_site, call_site, mixed_site } +); diff --git a/library/proc_macro/src/bridge/selfless_reify.rs b/library/proc_macro/src/bridge/selfless_reify.rs index 4ee4bb87c2bbd..907ad256e4b43 100644 --- a/library/proc_macro/src/bridge/selfless_reify.rs +++ b/library/proc_macro/src/bridge/selfless_reify.rs @@ -75,9 +75,10 @@ macro_rules! define_reify_functions { define_reify_functions! { fn _reify_to_extern_c_fn_unary<A, R> for extern "C" fn(arg: A) -> R; - // HACK(eddyb) this abstraction is used with `for<'a> fn(Bridge<'a>) -> T` - // but that doesn't work with just `reify_to_extern_c_fn_unary` because of - // the `fn` pointer type being "higher-ranked" (i.e. the `for<'a>` binder). - // FIXME(eddyb) try to remove the lifetime from `Bridge`, that'd help. - fn reify_to_extern_c_fn_hrt_bridge<R> for extern "C" fn(bridge: super::Bridge<'_>) -> R; + // HACK(eddyb) this abstraction is used with `for<'a> fn(BridgeConfig<'a>) + // -> T` but that doesn't work with just `reify_to_extern_c_fn_unary` + // because of the `fn` pointer type being "higher-ranked" (i.e. the + // `for<'a>` binder). + // FIXME(eddyb) try to remove the lifetime from `BridgeConfig`, that'd help. + fn reify_to_extern_c_fn_hrt_bridge<R> for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R; } diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 3672299f18f48..ea8b833b48fde 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -8,8 +8,6 @@ use super::client::HandleStore; pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; - type Group: 'static + Clone; - type Punct: 'static + Copy + Eq + Hash; type Ident: 'static + Copy + Eq + Hash; type Literal: 'static + Clone; type SourceFile: 'static + Clone; @@ -38,14 +36,21 @@ macro_rules! declare_server_traits { $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* })* - pub trait Server: Types $(+ $name)* {} - impl<S: Types $(+ $name)*> Server for S {} + pub trait Server: Types $(+ $name)* { + fn globals(&mut self) -> ExpnGlobals<Self::Span>; + } } } with_api!(Self, self_, declare_server_traits); pub(super) struct MarkedTypes<S: Types>(S); +impl<S: Server> Server for MarkedTypes<S> { + fn globals(&mut self) -> ExpnGlobals<Self::Span> { + <_>::mark(Server::globals(&mut self.0)) + } +} + macro_rules! define_mark_types_impls { ($($name:ident { $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* @@ -120,7 +125,7 @@ pub trait ExecutionStrategy { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, + run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer; } @@ -132,13 +137,13 @@ impl ExecutionStrategy for SameThread { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, + run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { let mut dispatch = |buf| dispatcher.dispatch(buf); - run_client(Bridge { - cached_buffer: input, + run_client(BridgeConfig { + input, dispatch: (&mut dispatch).into(), force_show_panics, _marker: marker::PhantomData, @@ -156,7 +161,7 @@ impl ExecutionStrategy for CrossThread1 { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, + run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { use std::sync::mpsc::channel; @@ -170,8 +175,8 @@ impl ExecutionStrategy for CrossThread1 { res_rx.recv().unwrap() }; - run_client(Bridge { - cached_buffer: input, + run_client(BridgeConfig { + input, dispatch: (&mut dispatch).into(), force_show_panics, _marker: marker::PhantomData, @@ -193,7 +198,7 @@ impl ExecutionStrategy for CrossThread2 { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, + run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { use std::sync::{Arc, Mutex}; @@ -219,8 +224,8 @@ impl ExecutionStrategy for CrossThread2 { } }; - let r = run_client(Bridge { - cached_buffer: input, + let r = run_client(BridgeConfig { + input, dispatch: (&mut dispatch).into(), force_show_panics, _marker: marker::PhantomData, @@ -258,14 +263,16 @@ fn run_server< handle_counters: &'static client::HandleCounters, server: S, input: I, - run_client: extern "C" fn(Bridge<'_>) -> Buffer, + run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Result<O, PanicMessage> { let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; + let globals = dispatcher.server.globals(); + let mut buf = Buffer::new(); - input.encode(&mut buf, &mut dispatcher.handle_store); + (globals, input).encode(&mut buf, &mut dispatcher.handle_store); buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 5e1289ec79d30..9ab5061c66807 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -60,7 +60,7 @@ use std::{error, fmt, iter}; /// inside of a procedural macro, false if invoked from any other binary. #[stable(feature = "proc_macro_is_available", since = "1.57.0")] pub fn is_available() -> bool { - bridge::Bridge::is_available() + bridge::client::is_available() } /// The main type provided by this crate, representing an abstract stream of @@ -212,8 +212,8 @@ pub use quote::{quote, quote_span}; fn tree_to_bridge_tree( tree: TokenTree, ) -> bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, + bridge::client::TokenStream, + bridge::client::Span, bridge::client::Ident, bridge::client::Literal, > { @@ -238,8 +238,8 @@ impl From<TokenTree> for TokenStream { struct ConcatTreesHelper { trees: Vec< bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, + bridge::client::TokenStream, + bridge::client::Span, bridge::client::Ident, bridge::client::Literal, >, @@ -365,8 +365,8 @@ pub mod token_stream { pub struct IntoIter( std::vec::IntoIter< bridge::TokenTree< - bridge::client::Group, - bridge::client::Punct, + bridge::client::TokenStream, + bridge::client::Span, bridge::client::Ident, bridge::client::Literal, >, @@ -788,7 +788,7 @@ impl fmt::Display for TokenTree { /// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. #[derive(Clone)] #[stable(feature = "proc_macro_lib2", since = "1.29.0")] -pub struct Group(bridge::client::Group); +pub struct Group(bridge::Group<bridge::client::TokenStream, bridge::client::Span>); #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Send for Group {} @@ -825,13 +825,17 @@ impl Group { /// method below. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { - Group(bridge::client::Group::new(delimiter, stream.0)) + Group(bridge::Group { + delimiter, + stream: stream.0, + span: bridge::DelimSpan::from_single(Span::call_site().0), + }) } /// Returns the delimiter of this `Group` #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn delimiter(&self) -> Delimiter { - self.0.delimiter() + self.0.delimiter } /// Returns the `TokenStream` of tokens that are delimited in this `Group`. @@ -840,7 +844,7 @@ impl Group { /// returned above. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn stream(&self) -> TokenStream { - TokenStream(Some(self.0.stream())) + TokenStream(self.0.stream.clone()) } /// Returns the span for the delimiters of this token stream, spanning the @@ -852,7 +856,7 @@ impl Group { /// ``` #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { - Span(self.0.span()) + Span(self.0.span.entire) } /// Returns the span pointing to the opening delimiter of this group. @@ -863,7 +867,7 @@ impl Group { /// ``` #[stable(feature = "proc_macro_group_span", since = "1.55.0")] pub fn span_open(&self) -> Span { - Span(self.0.span_open()) + Span(self.0.span.open) } /// Returns the span pointing to the closing delimiter of this group. @@ -874,7 +878,7 @@ impl Group { /// ``` #[stable(feature = "proc_macro_group_span", since = "1.55.0")] pub fn span_close(&self) -> Span { - Span(self.0.span_close()) + Span(self.0.span.close) } /// Configures the span for this `Group`'s delimiters, but not its internal @@ -885,7 +889,7 @@ impl Group { /// tokens at the level of the `Group`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { - self.0.set_span(span.0); + self.0.span = bridge::DelimSpan::from_single(span.0); } } @@ -925,7 +929,7 @@ impl fmt::Debug for Group { /// forms of `Spacing` returned. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] -pub struct Punct(bridge::client::Punct); +pub struct Punct(bridge::Punct<bridge::client::Span>); #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Send for Punct {} @@ -958,13 +962,24 @@ impl Punct { /// which can be further configured with the `set_span` method below. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn new(ch: char, spacing: Spacing) -> Punct { - Punct(bridge::client::Punct::new(ch, spacing)) + const LEGAL_CHARS: &[char] = &[ + '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';', + ':', '#', '$', '?', '\'', + ]; + if !LEGAL_CHARS.contains(&ch) { + panic!("unsupported character `{:?}`", ch); + } + Punct(bridge::Punct { + ch: ch as u8, + joint: spacing == Spacing::Joint, + span: Span::call_site().0, + }) } /// Returns the value of this punctuation character as `char`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn as_char(&self) -> char { - self.0.as_char() + self.0.ch as char } /// Returns the spacing of this punctuation character, indicating whether it's immediately @@ -973,28 +988,19 @@ impl Punct { /// (`Alone`) so the operator has certainly ended. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn spacing(&self) -> Spacing { - self.0.spacing() + if self.0.joint { Spacing::Joint } else { Spacing::Alone } } /// Returns the span for this punctuation character. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { - Span(self.0.span()) + Span(self.0.span) } /// Configure the span for this punctuation character. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { - self.0 = self.0.with_span(span.0); - } -} - -// N.B., the bridge only provides `to_string`, implement `fmt::Display` -// based on it (the reverse of the usual relationship between the two). -#[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl ToString for Punct { - fn to_string(&self) -> String { - TokenStream::from(TokenTree::from(self.clone())).to_string() + self.0.span = span.0; } } @@ -1003,7 +1009,7 @@ impl ToString for Punct { #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Punct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.to_string()) + write!(f, "{}", self.as_char()) } } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index d554ec590358f..a05e0db3af716 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -102,7 +102,7 @@ pub use alloc_crate::alloc::*; /// if !ret.is_null() { /// ALLOCATED.fetch_add(layout.size(), SeqCst); /// } -/// return ret +/// ret /// } /// /// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 87f213b160830..ff7b70c328daf 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -156,7 +156,7 @@ use core::array; use core::convert::Infallible; use crate::alloc::{AllocError, LayoutError}; -use crate::any::TypeId; +use crate::any::{Demand, Provider, TypeId}; use crate::backtrace::Backtrace; use crate::borrow::Cow; use crate::cell; @@ -295,6 +295,85 @@ pub trait Error: Debug + Display { fn cause(&self) -> Option<&dyn Error> { self.source() } + + /// Provides type based access to context intended for error reports. + /// + /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// # Example + /// + /// ```rust + /// #![feature(provide_any)] + /// #![feature(error_generic_member_access)] + /// use core::fmt; + /// use core::any::Demand; + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SourceError { + /// // ... + /// } + /// + /// impl fmt::Display for SourceError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Source Error") + /// } + /// } + /// + /// impl std::error::Error for SourceError {} + /// + /// #[derive(Debug)] + /// struct Error { + /// source: SourceError, + /// backtrace: MyBacktrace, + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Error") + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { + /// req + /// .provide_ref::<MyBacktrace>(&self.backtrace) + /// .provide_ref::<dyn std::error::Error + 'static>(&self.source); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let source = SourceError {}; + /// let error = Error { source, backtrace }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = dyn_error.request_ref::<MyBacktrace>().unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(unused_variables)] + fn provide<'a>(&'a self, req: &mut Demand<'a>) {} +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl Provider for dyn Error + 'static { + fn provide<'a>(&'a self, req: &mut Demand<'a>) { + self.provide(req) + } } mod private { @@ -831,6 +910,18 @@ impl dyn Error + 'static { None } } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> { + core::any::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value<T: 'static>(&self) -> Option<T> { + core::any::request_value(self) + } } impl dyn Error + 'static + Send { @@ -854,6 +945,18 @@ impl dyn Error + 'static + Send { pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { <dyn Error + 'static>::downcast_mut::<T>(self) } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> { + <dyn Error + 'static>::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value<T: 'static>(&self) -> Option<T> { + <dyn Error + 'static>::request_value(self) + } } impl dyn Error + 'static + Send + Sync { @@ -877,6 +980,18 @@ impl dyn Error + 'static + Send + Sync { pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { <dyn Error + 'static>::downcast_mut::<T>(self) } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> { + <dyn Error + 'static>::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value<T: 'static>(&self) -> Option<T> { + <dyn Error + 'static>::request_value(self) + } } impl dyn Error { diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 94ae97a2e402a..d987bf69b2576 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -146,28 +146,20 @@ #![stable(feature = "rust1", since = "1.0.0")] -/// See [alloc::ffi::FromVecWithNulError]. -#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] -pub type FromVecWithNulError = alloc::ffi::FromVecWithNulError; -/// See [alloc::ffi::CString]. -#[stable(feature = "rust1", since = "1.0.0")] -pub type CString = alloc::ffi::CString; -/// See [alloc::ffi::IntoStringError]. -#[stable(feature = "rust1", since = "1.0.0")] -pub type IntoStringError = alloc::ffi::IntoStringError; -/// See [alloc::ffi::NulError]. -#[stable(feature = "rust1", since = "1.0.0")] -pub type NulError = alloc::ffi::NulError; -/// See [core::ffi::CStr]. -#[stable(feature = "rust1", since = "1.0.0")] -pub type CStr = core::ffi::CStr; -/// See [core::ffi::FromBytesWithNulError]. -#[stable(feature = "cstr_from_bytes", since = "1.10.0")] -pub type FromBytesWithNulError = core::ffi::FromBytesWithNulError; +#[stable(feature = "alloc_c_string", since = "1.64.0")] +pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError}; +#[stable(feature = "core_c_str", since = "1.64.0")] +pub use core::ffi::{CStr, FromBytesWithNulError}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::os_str::{OsStr, OsString}; +#[stable(feature = "core_ffi_c", since = "1.64.0")] +pub use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, +}; + #[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f2bbcc85cecda..a0a5c003d281a 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -643,6 +643,14 @@ impl Hash for OsString { } } +#[stable(feature = "os_string_fmt_write", since = "1.64.0")] +impl fmt::Write for OsString { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.push(s); + Ok(()) + } +} + impl OsStr { /// Coerces into an `OsStr` slice. /// diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f46997b807ab2..d799776548a65 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -295,6 +295,9 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> { /// This function will create a file if it does not exist, /// and will entirely replace its contents if it does. /// +/// Depending on the platform, this function may fail if the +/// full directory path does not exist. +/// /// This is a convenience function for using [`File::create`] and [`write_all`] /// with fewer imports. /// @@ -349,6 +352,9 @@ impl File { /// This function will create a file if it does not exist, /// and will truncate it if it does. /// + /// Depending on the platform, this function may fail if the + /// full directory path does not exist. + /// /// See the [`OpenOptions::open`] function for more details. /// /// # Examples diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 0ce6ae00ee250..f3fbfc4478951 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -396,38 +396,99 @@ fn slice_write_vectored( Ok(nwritten) } -// Resizing write implementation -fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize> -where - A: Allocator, -{ +/// Reserves the required space, and pads the vec with 0s if necessary. +fn reserve_and_pad<A: Allocator>( + pos_mut: &mut u64, + vec: &mut Vec<u8, A>, + buf_len: usize, +) -> io::Result<usize> { let pos: usize = (*pos_mut).try_into().map_err(|_| { io::const_io_error!( ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length", ) })?; - // Make sure the internal buffer is as least as big as where we - // currently are - let len = vec.len(); - if len < pos { - // use `resize` so that the zero filling is as efficient as possible - vec.resize(pos, 0); - } - // Figure out what bytes will be used to overwrite what's currently - // there (left), and what will be appended on the end (right) - { - let space = vec.len() - pos; - let (left, right) = buf.split_at(cmp::min(space, buf.len())); - vec[pos..pos + left.len()].copy_from_slice(left); - vec.extend_from_slice(right); + + // For safety reasons, we don't want these numbers to overflow + // otherwise our allocation won't be enough + let desired_cap = pos.saturating_add(buf_len); + if desired_cap > vec.capacity() { + // We want our vec's total capacity + // to have room for (pos+buf_len) bytes. Reserve allocates + // based on additional elements from the length, so we need to + // reserve the difference + vec.reserve(desired_cap - vec.len()); + } + // Pad if pos is above the current len. + if pos > vec.len() { + let diff = pos - vec.len(); + // Unfortunately, `resize()` would suffice but the optimiser does not + // realise the `reserve` it does can be eliminated. So we do it manually + // to eliminate that extra branch + let spare = vec.spare_capacity_mut(); + debug_assert!(spare.len() >= diff); + // Safety: we have allocated enough capacity for this. + // And we are only writing, not reading + unsafe { + spare.get_unchecked_mut(..diff).fill(core::mem::MaybeUninit::new(0)); + vec.set_len(pos); + } } + Ok(pos) +} + +/// Writes the slice to the vec without allocating +/// # Safety: vec must have buf.len() spare capacity +unsafe fn vec_write_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize +where + A: Allocator, +{ + debug_assert!(vec.capacity() >= pos + buf.len()); + vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()); + pos + buf.len() +} + +/// Resizing write implementation for [`Cursor`] +/// +/// Cursor is allowed to have a pre-allocated and initialised +/// vector body, but with a position of 0. This means the [`Write`] +/// will overwrite the contents of the vec. +/// +/// This also allows for the vec body to be empty, but with a position of N. +/// This means that [`Write`] will pad the vec with 0 initially, +/// before writing anything from that point +fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize> +where + A: Allocator, +{ + let buf_len = buf.len(); + let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?; + + // Write the buf then progress the vec forward if necessary + // Safety: we have ensured that the capacity is available + // and that all bytes get written up to pos + unsafe { + pos = vec_write_unchecked(pos, vec, buf); + if pos > vec.len() { + vec.set_len(pos); + } + }; + // Bump us forward - *pos_mut = (pos + buf.len()) as u64; - Ok(buf.len()) + *pos_mut += buf_len as u64; + Ok(buf_len) } +/// Resizing write_vectored implementation for [`Cursor`] +/// +/// Cursor is allowed to have a pre-allocated and initialised +/// vector body, but with a position of 0. This means the [`Write`] +/// will overwrite the contents of the vec. +/// +/// This also allows for the vec body to be empty, but with a position of N. +/// This means that [`Write`] will pad the vec with 0 initially, +/// before writing anything from that point fn vec_write_vectored<A>( pos_mut: &mut u64, vec: &mut Vec<u8, A>, @@ -436,11 +497,26 @@ fn vec_write_vectored<A>( where A: Allocator, { - let mut nwritten = 0; - for buf in bufs { - nwritten += vec_write(pos_mut, vec, buf)?; + // For safety reasons, we don't want this sum to overflow ever. + // If this saturates, the reserve should panic to avoid any unsound writing. + let buf_len = bufs.iter().fold(0usize, |a, b| a.saturating_add(b.len())); + let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?; + + // Write the buf then progress the vec forward if necessary + // Safety: we have ensured that the capacity is available + // and that all bytes get written up to the last pos + unsafe { + for buf in bufs { + pos = vec_write_unchecked(pos, vec, buf); + } + if pos > vec.len() { + vec.set_len(pos); + } } - Ok(nwritten) + + // Bump us forward + *pos_mut += buf_len as u64; + Ok(buf_len) } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs index f1ee177b7f3bc..d7c203c297fe6 100644 --- a/library/std/src/io/cursor/tests.rs +++ b/library/std/src/io/cursor/tests.rs @@ -20,6 +20,7 @@ fn test_vec_writer() { #[test] fn test_mem_writer() { let mut writer = Cursor::new(Vec::new()); + writer.set_position(10); assert_eq!(writer.write(&[0]).unwrap(), 1); assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); @@ -30,6 +31,17 @@ fn test_mem_writer() { 3 ); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(&writer.get_ref()[..10], &[0; 10]); + assert_eq!(&writer.get_ref()[10..], b); +} + +#[test] +fn test_mem_writer_preallocated() { + let mut writer = Cursor::new(vec![0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10]); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(&writer.get_ref()[..], b); } @@ -517,3 +529,39 @@ fn const_cursor() { const _: &&[u8] = CURSOR.get_ref(); const _: u64 = CURSOR.position(); } + +#[bench] +fn bench_write_vec(b: &mut test::Bencher) { + let slice = &[1; 128]; + + b.iter(|| { + let mut buf = b"some random data to overwrite".to_vec(); + let mut cursor = Cursor::new(&mut buf); + + let _ = cursor.write_all(slice); + test::black_box(&cursor); + }) +} + +#[bench] +fn bench_write_vec_vectored(b: &mut test::Bencher) { + let slices = [ + IoSlice::new(&[1; 128]), + IoSlice::new(&[2; 256]), + IoSlice::new(&[3; 512]), + IoSlice::new(&[4; 1024]), + IoSlice::new(&[5; 2048]), + IoSlice::new(&[6; 4096]), + IoSlice::new(&[7; 8192]), + IoSlice::new(&[8; 8192 * 2]), + ]; + + b.iter(|| { + let mut buf = b"some random data to overwrite".to_vec(); + let mut cursor = Cursor::new(&mut buf); + + let mut slices = slices; + let _ = cursor.write_all_vectored(&mut slices); + test::black_box(&cursor); + }) +} diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 4a50e647c640e..ff7fdcae16f53 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -795,6 +795,68 @@ impl Error { } } + /// Attempt to downgrade the inner error to `E` if any. + /// + /// If this [`Error`] was constructed via [`new`] then this function will + /// attempt to perform downgrade on it, otherwise it will return [`Err`]. + /// + /// If downgrade succeeds, it will return [`Ok`], otherwise it will also + /// return [`Err`]. + /// + /// [`new`]: Error::new + /// + /// # Examples + /// + /// ``` + /// #![feature(io_error_downcast)] + /// + /// use std::fmt; + /// use std::io; + /// use std::error::Error; + /// + /// #[derive(Debug)] + /// enum E { + /// Io(io::Error), + /// SomeOtherVariant, + /// } + /// + /// impl fmt::Display for E { + /// // ... + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # todo!() + /// # } + /// } + /// impl Error for E {} + /// + /// impl From<io::Error> for E { + /// fn from(err: io::Error) -> E { + /// err.downcast::<E>() + /// .map(|b| *b) + /// .unwrap_or_else(E::Io) + /// } + /// } + /// ``` + #[unstable(feature = "io_error_downcast", issue = "99262")] + pub fn downcast<E>(self) -> result::Result<Box<E>, Self> + where + E: error::Error + Send + Sync + 'static, + { + match self.repr.into_data() { + ErrorData::Custom(b) if b.error.is::<E>() => { + let res = (*b).error.downcast::<E>(); + + // downcast is a really trivial and is marked as inline, so + // it's likely be inlined here. + // + // And the compiler should be able to eliminate the branch + // that produces `Err` here since b.error.is::<E>() + // returns true. + Ok(res.unwrap()) + } + repr_data => Err(Self { repr: Repr::new(repr_data) }), + } + } + /// Returns the corresponding [`ErrorKind`] for this error. /// /// # Examples diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index e80068b46abb9..292bf4826fd23 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -132,6 +132,15 @@ unsafe impl Send for Repr {} unsafe impl Sync for Repr {} impl Repr { + pub(super) fn new(dat: ErrorData<Box<Custom>>) -> Self { + match dat { + ErrorData::Os(code) => Self::new_os(code), + ErrorData::Simple(kind) => Self::new_simple(kind), + ErrorData::SimpleMessage(simple_message) => Self::new_simple_message(simple_message), + ErrorData::Custom(b) => Self::new_custom(b), + } + } + pub(super) fn new_custom(b: Box<Custom>) -> Self { let p = Box::into_raw(b).cast::<u8>(); // Should only be possible if an allocator handed out a pointer with diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/std/src/io/error/repr_unpacked.rs index 3729c039c42d7..d6ad55b99f5c0 100644 --- a/library/std/src/io/error/repr_unpacked.rs +++ b/library/std/src/io/error/repr_unpacked.rs @@ -10,6 +10,10 @@ type Inner = ErrorData<Box<Custom>>; pub(super) struct Repr(Inner); impl Repr { + #[inline] + pub(super) fn new(dat: ErrorData<Box<Custom>>) -> Self { + Self(dat) + } pub(super) fn new_custom(b: Box<Custom>) -> Self { Self(Inner::Custom(b)) } diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index 8d7877bcad35d..c897a5e8701c4 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -1,4 +1,4 @@ -use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr}; +use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage}; use crate::assert_matches::assert_matches; use crate::error; use crate::fmt; @@ -141,3 +141,54 @@ fn test_custom_error_packing() { }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)), ); } + +#[derive(Debug)] +struct E; + +impl fmt::Display for E { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl error::Error for E {} + +#[test] +fn test_std_io_error_downcast() { + // Case 1: custom error, downcast succeeds + let io_error = Error::new(ErrorKind::Other, Bojji(true)); + let e: Box<Bojji> = io_error.downcast().unwrap(); + assert!(e.0); + + // Case 2: custom error, downcast fails + let io_error = Error::new(ErrorKind::Other, Bojji(true)); + let io_error = io_error.downcast::<E>().unwrap_err(); + + // ensures that the custom error is intact + assert_eq!(ErrorKind::Other, io_error.kind()); + let e: Box<Bojji> = io_error.downcast().unwrap(); + assert!(e.0); + + // Case 3: os error + let errno = 20; + let io_error = Error::from_raw_os_error(errno); + let io_error = io_error.downcast::<E>().unwrap_err(); + + assert_eq!(errno, io_error.raw_os_error().unwrap()); + + // Case 4: simple + let kind = ErrorKind::OutOfMemory; + let io_error: Error = kind.into(); + let io_error = io_error.downcast::<E>().unwrap_err(); + + assert_eq!(kind, io_error.kind()); + + // Case 5: simple message + const SIMPLE_MESSAGE: SimpleMessage = + SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" }; + let io_error = Error::from_static_message(&SIMPLE_MESSAGE); + let io_error = io_error.downcast::<E>().unwrap_err(); + + assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind()); + assert_eq!(SIMPLE_MESSAGE.message, &*format!("{io_error}")); +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7da9f248c877a..9fd426d3ac4e2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -210,9 +210,11 @@ #![allow(unused_lifetimes)] // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] +// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` +#![cfg_attr(not(bootstrap), deny(ffi_unwind_calls))] // std may use features in a platform-specific way #![allow(unused_features)] -#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))] +#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) @@ -241,7 +243,7 @@ #![feature(intra_doc_pointers)] #![feature(label_break_value)] #![feature(lang_items)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(linkage)] #![feature(min_specialization)] @@ -249,7 +251,6 @@ #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] -#![cfg_attr(bootstrap, feature(nll))] #![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(rustc_attrs)] @@ -263,13 +264,13 @@ #![feature(atomic_mut_ptr)] #![feature(char_error_internals)] #![feature(char_internals)] -#![feature(core_c_str)] #![feature(core_intrinsics)] #![feature(cstr_from_bytes_until_nul)] #![feature(cstr_internals)] #![feature(duration_checked_float)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] +#![feature(exclusive_wrapper)] #![feature(extend_one)] #![feature(float_minimum_maximum)] #![feature(hasher_prefixfree_extras)] @@ -284,6 +285,7 @@ #![feature(panic_internals)] #![feature(portable_simd)] #![feature(prelude_2024)] +#![feature(provide_any)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] #![feature(slice_internals)] @@ -294,7 +296,6 @@ // // Library features (alloc): #![feature(alloc_layout_extra)] -#![feature(alloc_c_string)] #![feature(allocator_api)] #![feature(get_mut_unchecked)] #![feature(map_try_insert)] @@ -315,7 +316,6 @@ #![feature(cfg_eval)] #![feature(concat_bytes)] #![feature(const_format_args)] -#![feature(core_ffi_c)] #![feature(core_panic)] #![feature(custom_test_frameworks)] #![feature(edition_panic)] @@ -335,7 +335,6 @@ #![feature(const_ip)] #![feature(const_ipv4)] #![feature(const_ipv6)] -#![feature(const_option)] #![feature(const_socketaddr)] #![feature(thread_local_internals)] // @@ -585,7 +584,7 @@ mod backtrace_rs; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::{ - assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo, + assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, todo, r#try, unimplemented, unreachable, write, writeln, }; diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 06300035633b9..69b72a81c5b6d 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -7,6 +7,7 @@ use crate::io::prelude::*; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; +use crate::iter::FusedIterator; use crate::net::{Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys_common::net as net_imp; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -1009,6 +1010,9 @@ impl<'a> Iterator for Incoming<'a> { } } +#[stable(feature = "tcp_listener_incoming_fused_iterator", since = "1.64.0")] +impl FusedIterator for Incoming<'_> {} + #[unstable(feature = "tcplistener_into_incoming", issue = "88339")] impl Iterator for IntoIncoming { type Item = io::Result<TcpStream>; @@ -1017,6 +1021,9 @@ impl Iterator for IntoIncoming { } } +#[unstable(feature = "tcplistener_into_incoming", issue = "88339")] +impl FusedIterator for IntoIncoming {} + impl AsInner<net_imp::TcpListener> for TcpListener { fn as_inner(&self) -> &net_imp::TcpListener { &self.0 diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index dd965ddc01eef..d661a13edc5e5 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -355,3 +355,34 @@ impl From<OwnedFd> for crate::net::UdpSocket { )))) } } + +#[stable(feature = "io_safety", since = "1.63.0")] +/// This impl allows implementing traits that require `AsFd` on Arc. +/// ``` +/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg { +/// # #[cfg(target_os = "wasi")] +/// # use std::os::wasi::io::AsFd; +/// # #[cfg(unix)] +/// # use std::os::unix::io::AsFd; +/// use std::net::UdpSocket; +/// use std::sync::Arc; +/// +/// trait MyTrait: AsFd {} +/// impl MyTrait for Arc<UdpSocket> {} +/// impl MyTrait for Box<UdpSocket> {} +/// # } +/// ``` +impl<T: AsFd> AsFd for crate::sync::Arc<T> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + (**self).as_fd() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl<T: AsFd> AsFd for Box<T> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + (**self).as_fd() + } +} diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 47ee88d97fb93..ff4e25b792ad0 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -73,7 +73,7 @@ pub trait FromRawFd { /// /// # Safety /// - /// The `fd` passed in must be a valid an open file descriptor. + /// The `fd` passed in must be a valid and open file descriptor. /// /// # Example /// @@ -222,3 +222,34 @@ impl<'a> AsRawFd for io::StderrLock<'a> { libc::STDERR_FILENO } } + +/// This impl allows implementing traits that require `AsRawFd` on Arc. +/// ``` +/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg { +/// # #[cfg(target_os = "wasi")] +/// # use std::os::wasi::io::AsRawFd; +/// # #[cfg(unix)] +/// # use std::os::unix::io::AsRawFd; +/// use std::net::UdpSocket; +/// use std::sync::Arc; +/// trait MyTrait: AsRawFd { +/// } +/// impl MyTrait for Arc<UdpSocket> {} +/// impl MyTrait for Box<UdpSocket> {} +/// # } +/// ``` +#[stable(feature = "asrawfd_ptrs", since = "1.63.0")] +impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + (**self).as_raw_fd() + } +} + +#[stable(feature = "asrawfd_ptrs", since = "1.63.0")] +impl<T: AsRawFd> AsRawFd for Box<T> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + (**self).as_raw_fd() + } +} diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 5065530e8d4d0..09b2bfe39f094 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -148,9 +148,36 @@ pub trait CommandExt: Sealed { where S: AsRef<OsStr>; - /// Sets the process group ID of the child process. Translates to a `setpgid` call in the child - /// process. - #[unstable(feature = "process_set_process_group", issue = "93857")] + /// Sets the process group ID (PGID) of the child process. Equivalent to a + /// `setpgid` call in the child process, but may be more efficient. + /// + /// Process groups determine which processes receive signals. + /// + /// # Examples + /// + /// Pressing Ctrl-C in a terminal will send SIGINT to all processes in + /// the current foreground process group. By spawning the `sleep` + /// subprocess in a new process group, it will not receive SIGINT from the + /// terminal. + /// + /// The parent process could install a signal handler and manage the + /// subprocess on its own terms. + /// + /// A process group ID of 0 will use the process ID as the PGID. + /// + /// ```no_run + /// use std::process::Command; + /// use std::os::unix::process::CommandExt; + /// + /// Command::new("sleep") + /// .arg("10") + /// .process_group(0) + /// .spawn()? + /// .wait()?; + /// # + /// # Ok::<_, Box<dyn std::error::Error>>(()) + /// ``` + #[stable(feature = "process_set_process_group", since = "1.64.0")] fn process_group(&mut self, pgroup: i32) -> &mut process::Command; } diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs index a9493a94cac26..96bab59d3f8d7 100644 --- a/library/std/src/os/windows/ffi.rs +++ b/library/std/src/os/windows/ffi.rs @@ -129,6 +129,7 @@ pub trait OsStrExt: Sealed { #[stable(feature = "rust1", since = "1.0.0")] impl OsStrExt for OsStr { + #[inline] fn encode_wide(&self) -> EncodeWide<'_> { self.as_inner().inner.encode_wide() } diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index a6b75493e6e60..073168cf2d209 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -234,3 +234,26 @@ impl ChildExt for process::Child { self.handle.main_thread_handle() } } + +/// Windows-specific extensions to [`process::ExitCode`]. +/// +/// This trait is sealed: it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. +#[unstable(feature = "windows_process_exit_code_from", issue = "none")] +pub trait ExitCodeExt: Sealed { + /// Creates a new `ExitCode` from the raw underlying `u32` return value of + /// a process. + /// + /// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE` + /// macro returned from the `GetExitCodeProcess` function to signal that the + /// process has yet to run to completion. + #[unstable(feature = "windows_process_exit_code_from", issue = "none")] + fn from_raw(raw: u32) -> Self; +} + +#[unstable(feature = "windows_process_exit_code_from", issue = "none")] +impl ExitCodeExt for process::ExitCode { + fn from_raw(raw: u32) -> Self { + process::ExitCode::from_inner(From::from(raw)) + } +} diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index ac16f476143ce..45bc56efb3b99 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -11,7 +11,7 @@ use crate::thread::Result; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic)] +#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic, rt)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 00793f7f9204d..401c8159988bb 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -996,7 +996,7 @@ impl<T> (T,) {} // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(tuple_variadic))] +#[doc(tuple_variadic)] /// This trait is implemented on arbitrary-length tuples. impl<T: Clone> Clone for (T,) { fn clone(&self) -> Self { @@ -1007,7 +1007,7 @@ impl<T: Clone> Clone for (T,) { // Fake impl that's only really used for docs. #[cfg(doc)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(bootstrap), doc(tuple_variadic))] +#[doc(tuple_variadic)] /// This trait is implemented on arbitrary-length tuples. impl<T: Copy> Copy for (T,) { // empty diff --git a/library/std/src/process.rs b/library/std/src/process.rs index ab1a1e6c76fa4..d6cba7e7598f6 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1724,6 +1724,10 @@ impl crate::error::Error for ExitStatusError {} #[stable(feature = "process_exitcode", since = "1.61.0")] pub struct ExitCode(imp::ExitCode); +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for ExitCode {} + #[stable(feature = "process_exitcode", since = "1.61.0")] impl ExitCode { /// The canonical `ExitCode` for successful termination on this platform. @@ -1814,6 +1818,18 @@ impl From<u8> for ExitCode { } } +impl AsInner<imp::ExitCode> for ExitCode { + fn as_inner(&self) -> &imp::ExitCode { + &self.0 + } +} + +impl FromInner<imp::ExitCode> for ExitCode { + fn from_inner(s: imp::ExitCode) -> ExitCode { + ExitCode(s) + } +} + impl Child { /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] /// error is returned. diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 5fc18fda6a83b..7b507a169b395 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -155,6 +155,8 @@ pub use alloc_crate::sync::{Arc, Weak}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +pub use core::sync::Exclusive; #[stable(feature = "rust1", since = "1.0.0")] pub use self::barrier::{Barrier, BarrierWaitResult}; diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 1192c08cb1a88..6e4a2cfc82afd 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -4,6 +4,7 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; use crate::ops::{Deref, DerefMut}; +use crate::ptr::NonNull; use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; use crate::sys_common::rwlock as sys; @@ -101,7 +102,12 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - lock: &'a RwLock<T>, + // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a + // `Ref` argument doesn't hold immutability for its whole scope, only until it drops. + // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` + // is preferable over `const* T` to allow for niche optimization. + data: NonNull<T>, + inner_lock: &'a sys::MovableRwLock, } #[stable(feature = "rust1", since = "1.0.0")] @@ -511,12 +517,21 @@ impl<T> From<T> for RwLock<T> { } impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { + /// Create a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`. + // SAFETY: if and only if `lock.inner.read()` (or `lock.inner.try_read()`) has been + // successfully called from the same thread before instantiating this object. unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> { - poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { lock }) + poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard { + data: NonNull::new_unchecked(lock.data.get()), + inner_lock: &lock.inner, + }) } } impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { + /// Create a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. + // SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been + // successfully called from the same thread before instantiating this object. unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> { poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard }) } @@ -555,7 +570,8 @@ impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.lock.data.get() } + // SAFETY: the conditions of `RwLockGuard::new` were satisfied when created. + unsafe { self.data.as_ref() } } } @@ -564,6 +580,7 @@ impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { type Target = T; fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. unsafe { &*self.lock.data.get() } } } @@ -571,6 +588,7 @@ impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. unsafe { &mut *self.lock.data.get() } } } @@ -578,8 +596,9 @@ impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. unsafe { - self.lock.inner.read_unlock(); + self.inner_lock.read_unlock(); } } } @@ -588,6 +607,7 @@ impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { fn drop(&mut self) { self.lock.poison.done(&self.poison); + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. unsafe { self.lock.inner.write_unlock(); } diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index 53aa2b1e38a91..08255c985f5eb 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -1,6 +1,6 @@ use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::mpsc::channel; -use crate::sync::{Arc, RwLock, TryLockError}; +use crate::sync::{Arc, RwLock, RwLockReadGuard, TryLockError}; use crate::thread; use rand::{self, Rng}; @@ -245,3 +245,15 @@ fn test_get_mut_poison() { Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"), } } + +#[test] +fn test_read_guard_covariance() { + fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {} + let j: i32 = 5; + let lock = RwLock::new(&j); + { + let i = 6; + do_stuff(lock.read().unwrap(), &i); + } + drop(lock); +} diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index 3f00160e55a25..22059ca0dbe10 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -3,6 +3,7 @@ use crate::ptr; use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sys::hermit::abi; use crate::sys::locks::Mutex; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; // The implementation is inspired by Andrew D. Birrell's paper @@ -14,14 +15,26 @@ pub struct Condvar { sem2: *const c_void, } -pub type MovableCondvar = Condvar; +pub(crate) type MovableCondvar = LazyBox<Condvar>; + +impl LazyInit for Condvar { + fn init() -> Box<Self> { + Box::new(Self::new()) + } +} unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} impl Condvar { - pub const fn new() -> Condvar { - Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() } + pub fn new() -> Self { + let mut condvar = + Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }; + unsafe { + let _ = abi::sem_init(&mut condvar.sem1, 0); + let _ = abi::sem_init(&mut condvar.sem2, 0); + } + condvar } pub unsafe fn notify_one(&self) { diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index ef44bf411fba5..eb15a04ffcffb 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -175,9 +175,7 @@ impl Mutex { } #[inline] - pub unsafe fn init(&mut self) { - self.inner = Spinlock::new(MutexInner::new()); - } + pub unsafe fn init(&mut self) {} #[inline] pub unsafe fn lock(&self) { diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index d43fa08a17150..9701bab1f660b 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -1,9 +1,10 @@ use crate::cell::UnsafeCell; -use crate::sys::locks::{Condvar, Mutex}; +use crate::sys::locks::{MovableCondvar, Mutex}; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct RwLock { lock: Mutex, - cond: Condvar, + cond: MovableCondvar, state: UnsafeCell<State>, } @@ -28,7 +29,11 @@ unsafe impl Sync for RwLock {} impl RwLock { pub const fn new() -> RwLock { - RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) } + RwLock { + lock: Mutex::new(), + cond: MovableCondvar::new(), + state: UnsafeCell::new(State::Unlocked), + } } #[inline] diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs index f99ee4fa897ea..5eb14bb7e534b 100644 --- a/library/std/src/sys/itron/abi.rs +++ b/library/std/src/sys/itron/abi.rs @@ -30,15 +30,32 @@ pub type ER = int_t; /// Error code type, `ID` on success pub type ER_ID = int_t; +/// Service call operational mode +pub type MODE = uint_t; + +/// OR waiting condition for an eventflag +pub const TWF_ORW: MODE = 0x01; + +/// Object attributes +pub type ATR = uint_t; + +/// FIFO wait order +pub const TA_FIFO: ATR = 0; +/// Only one task is allowed to be in the waiting state for the eventflag +pub const TA_WSGL: ATR = 0; +/// The eventflag’s bit pattern is cleared when a task is released from the +/// waiting state for that eventflag. +pub const TA_CLR: ATR = 0x04; + +/// Bit pattern of an eventflag +pub type FLGPTN = uint_t; + /// Task or interrupt priority pub type PRI = int_t; /// The special value of `PRI` representing the current task's priority. pub const TPRI_SELF: PRI = 0; -/// Object attributes -pub type ATR = uint_t; - /// Use the priority inheritance protocol #[cfg(target_os = "solid_asp3")] pub const TA_INHERIT: ATR = 0x02; @@ -90,6 +107,13 @@ pub struct T_CSEM { pub maxsem: uint_t, } +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CFLG { + pub flgatr: ATR, + pub iflgptn: FLGPTN, +} + #[derive(Clone, Copy)] #[repr(C)] pub struct T_CMTX { @@ -139,6 +163,24 @@ extern "C" { pub fn sns_dsp() -> bool_t; #[link_name = "__asp3_get_tim"] pub fn get_tim(p_systim: *mut SYSTIM) -> ER; + #[link_name = "__asp3_acre_flg"] + pub fn acre_flg(pk_cflg: *const T_CFLG) -> ER_ID; + #[link_name = "__asp3_del_flg"] + pub fn del_flg(flgid: ID) -> ER; + #[link_name = "__asp3_set_flg"] + pub fn set_flg(flgid: ID, setptn: FLGPTN) -> ER; + #[link_name = "__asp3_clr_flg"] + pub fn clr_flg(flgid: ID, clrptn: FLGPTN) -> ER; + #[link_name = "__asp3_wai_flg"] + pub fn wai_flg(flgid: ID, waiptn: FLGPTN, wfmode: MODE, p_flgptn: *mut FLGPTN) -> ER; + #[link_name = "__asp3_twai_flg"] + pub fn twai_flg( + flgid: ID, + waiptn: FLGPTN, + wfmode: MODE, + p_flgptn: *mut FLGPTN, + tmout: TMO, + ) -> ER; #[link_name = "__asp3_acre_mtx"] pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID; #[link_name = "__asp3_del_mtx"] diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs new file mode 100644 index 0000000000000..e432edd207754 --- /dev/null +++ b/library/std/src/sys/itron/wait_flag.rs @@ -0,0 +1,72 @@ +use crate::mem::MaybeUninit; +use crate::time::Duration; + +use super::{ + abi, + error::{expect_success, fail}, + time::with_tmos, +}; + +const CLEAR: abi::FLGPTN = 0; +const RAISED: abi::FLGPTN = 1; + +/// A thread parking primitive that is not susceptible to race conditions, +/// but provides no atomic ordering guarantees and allows only one `raise` per wait. +pub struct WaitFlag { + flag: abi::ID, +} + +impl WaitFlag { + /// Creates a new wait flag. + pub fn new() -> WaitFlag { + let flag = expect_success( + unsafe { + abi::acre_flg(&abi::T_CFLG { + flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR, + iflgptn: CLEAR, + }) + }, + &"acre_flg", + ); + + WaitFlag { flag } + } + + /// Wait for the wait flag to be raised. + pub fn wait(&self) { + let mut token = MaybeUninit::uninit(); + expect_success( + unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) }, + &"wai_flg", + ); + } + + /// Wait for the wait flag to be raised or the timeout to occur. + /// + /// Returns whether the flag was raised (`true`) or the operation timed out (`false`). + pub fn wait_timeout(&self, dur: Duration) -> bool { + let mut token = MaybeUninit::uninit(); + let res = with_tmos(dur, |tmout| unsafe { + abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout) + }); + + match res { + abi::E_OK => true, + abi::E_TMOUT => false, + error => fail(error, &"twai_flg"), + } + } + + /// Raise the wait flag. + /// + /// Calls to this function should be balanced with the number of successful waits. + pub fn raise(&self) { + expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg"); + } +} + +impl Drop for WaitFlag { + fn drop(&mut self) { + expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg"); + } +} diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 3792a3820a534..ea24fedd0eb3d 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -1,13 +1,16 @@ #![allow(unused)] +use crate::arch::asm; use crate::cell::UnsafeCell; +use crate::cmp; +use crate::convert::TryInto; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::ptr::{self, NonNull}; use crate::slice; use crate::slice::SliceIndex; -use super::super::mem::is_user_range; +use super::super::mem::{is_enclave_range, is_user_range}; use fortanix_sgx_abi::*; /// A type that can be safely read from or written to userspace. @@ -210,7 +213,9 @@ where unsafe { // Mustn't call alloc with size 0. let ptr = if size > 0 { - rtunwrap!(Ok, super::alloc(size, T::align_of())) as _ + // `copy_to_userspace` is more efficient when data is 8-byte aligned + let alignment = cmp::max(T::align_of(), 8); + rtunwrap!(Ok, super::alloc(size, alignment)) as _ } else { T::align_of() as _ // dangling pointer ok for size 0 }; @@ -225,13 +230,9 @@ where /// Copies `val` into freshly allocated space in user memory. pub fn new_from_enclave(val: &T) -> Self { unsafe { - let ret = Self::new_uninit_bytes(mem::size_of_val(val)); - ptr::copy( - val as *const T as *const u8, - ret.0.as_ptr() as *mut u8, - mem::size_of_val(val), - ); - ret + let mut user = Self::new_uninit_bytes(mem::size_of_val(val)); + user.copy_from_enclave(val); + user } } @@ -304,6 +305,105 @@ where } } +/// Copies `len` bytes of data from enclave pointer `src` to userspace `dst` +/// +/// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either: +/// - preceded by the VERW instruction and followed by the MFENCE; LFENCE instruction sequence +/// - or are in multiples of 8 bytes, aligned to an 8-byte boundary +/// +/// # Panics +/// This function panics if: +/// +/// * The `src` pointer is null +/// * The `dst` pointer is null +/// * The `src` memory range is not in enclave memory +/// * The `dst` memory range is not in user memory +/// +/// # References +/// - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html +/// - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html#inpage-nav-3-2-2 +pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + let mut seg_sel: u16 = 0; + for off in 0..len { + asm!(" + mov %ds, ({seg_sel}) + verw ({seg_sel}) + movb {val}, ({dst}) + mfence + lfence + ", + val = in(reg_byte) *src.offset(off as isize), + dst = in(reg) dst.offset(off as isize), + seg_sel = in(reg) &mut seg_sel, + options(nostack, att_syntax) + ); + } + } + } + + unsafe fn copy_aligned_quadwords_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + asm!( + "rep movsq (%rsi), (%rdi)", + inout("rcx") len / 8 => _, + inout("rdi") dst => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); + } + } + assert!(!src.is_null()); + assert!(!dst.is_null()); + assert!(is_enclave_range(src, len)); + assert!(is_user_range(dst, len)); + assert!(len < isize::MAX as usize); + assert!(!(src as usize).overflowing_add(len).1); + assert!(!(dst as usize).overflowing_add(len).1); + + if len < 8 { + // Can't align on 8 byte boundary: copy safely byte per byte + unsafe { + copy_bytewise_to_userspace(src, dst, len); + } + } else if len % 8 == 0 && dst as usize % 8 == 0 { + // Copying 8-byte aligned quadwords: copy quad word per quad word + unsafe { + copy_aligned_quadwords_to_userspace(src, dst, len); + } + } else { + // Split copies into three parts: + // +--------+ + // | small0 | Chunk smaller than 8 bytes + // +--------+ + // | big | Chunk 8-byte aligned, and size a multiple of 8 bytes + // +--------+ + // | small1 | Chunk smaller than 8 bytes + // +--------+ + + unsafe { + // Copy small0 + let small0_size = (8 - dst as usize % 8) as u8; + let small0_src = src; + let small0_dst = dst; + copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _); + + // Copy big + let small1_size = ((len - small0_size as usize) % 8) as u8; + let big_size = len - small0_size as usize - small1_size as usize; + let big_src = src.offset(small0_size as _); + let big_dst = dst.offset(small0_size as _); + copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size); + + // Copy small1 + let small1_src = src.offset(big_size as isize + small0_size as isize); + let small1_dst = dst.offset(big_size as isize + small0_size as isize); + copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _); + } + } +} + #[unstable(feature = "sgx_platform", issue = "56975")] impl<T: ?Sized> UserRef<T> where @@ -352,7 +452,7 @@ where pub fn copy_from_enclave(&mut self, val: &T) { unsafe { assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get())); - ptr::copy( + copy_to_userspace( val as *const T as *const u8, self.0.get() as *mut T as *mut u8, mem::size_of_val(val), diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index 2f99abba77667..79d1db5e1c50d 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -6,6 +6,8 @@ use crate::time::{Duration, Instant}; pub(crate) mod alloc; #[macro_use] pub(crate) mod raw; +#[cfg(test)] +mod tests; use self::raw::*; diff --git a/library/std/src/sys/sgx/abi/usercalls/tests.rs b/library/std/src/sys/sgx/abi/usercalls/tests.rs new file mode 100644 index 0000000000000..cbf7d7d54f7a2 --- /dev/null +++ b/library/std/src/sys/sgx/abi/usercalls/tests.rs @@ -0,0 +1,30 @@ +use super::alloc::copy_to_userspace; +use super::alloc::User; + +#[test] +fn test_copy_function() { + let mut src = [0u8; 100]; + let mut dst = User::<[u8]>::uninitialized(100); + + for i in 0..src.len() { + src[i] = i as _; + } + + for size in 0..48 { + // For all possible alignment + for offset in 0..8 { + // overwrite complete dst + dst.copy_from_enclave(&[0u8; 100]); + + // Copy src[0..size] to dst + offset + unsafe { copy_to_userspace(src.as_ptr(), dst.as_mut_ptr().offset(offset), size) }; + + // Verify copy + for byte in 0..size { + unsafe { + assert_eq!(*dst.as_ptr().offset(offset + byte as isize), src[byte as usize]); + } + } + } + } +} diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index 5ffa381f2e50f..2d21e4764fc21 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -15,6 +15,7 @@ mod itron { pub mod thread; pub(super) mod time; use super::unsupported; + pub mod wait_flag; } pub mod alloc; @@ -43,6 +44,7 @@ pub mod memchr; pub mod thread_local_dtor; pub mod thread_local_key; pub mod time; +pub use self::itron::wait_flag; mod rwlock; diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 916e898d8906e..98afee69ba622 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -1,5 +1,5 @@ use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; +use crate::mem::{forget, MaybeUninit}; use crate::sys::cvt_nz; use crate::sys_common::lazy_box::{LazyBox, LazyInit}; @@ -23,6 +23,24 @@ impl LazyInit for Mutex { unsafe { mutex.init() }; mutex } + + fn destroy(mutex: Box<Self>) { + // We're not allowed to pthread_mutex_destroy a locked mutex, + // so check first if it's unlocked. + if unsafe { mutex.try_lock() } { + unsafe { mutex.unlock() }; + drop(mutex); + } else { + // The mutex is locked. This happens if a MutexGuard is leaked. + // In this case, we just leak the Mutex too. + forget(mutex); + } + } + + fn cancel_init(_: Box<Self>) { + // In this case, we can just drop it without any checks, + // since it cannot have been locked yet. + } } impl Mutex { diff --git a/library/std/src/sys/unix/locks/pthread_rwlock.rs b/library/std/src/sys/unix/locks/pthread_rwlock.rs index 75e5759c7879d..adfe2a88338f5 100644 --- a/library/std/src/sys/unix/locks/pthread_rwlock.rs +++ b/library/std/src/sys/unix/locks/pthread_rwlock.rs @@ -1,4 +1,5 @@ use crate::cell::UnsafeCell; +use crate::mem::forget; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys_common::lazy_box::{LazyBox, LazyInit}; @@ -17,6 +18,21 @@ impl LazyInit for RwLock { fn init() -> Box<Self> { Box::new(Self::new()) } + + fn destroy(mut rwlock: Box<Self>) { + // We're not allowed to pthread_rwlock_destroy a locked rwlock, + // so check first if it's unlocked. + if *rwlock.write_locked.get_mut() || *rwlock.num_readers.get_mut() != 0 { + // The rwlock is locked. This happens if a RwLock{Read,Write}Guard is leaked. + // In this case, we just leak the RwLock too. + forget(rwlock); + } + } + + fn cancel_init(_: Box<Self>) { + // In this case, we can just drop it without any checks, + // since it cannot have been locked yet. + } } impl RwLock { diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index c5918103fec25..01f26298290f0 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -21,6 +21,17 @@ use crate::vec; use core::iter; +/// This is the const equivalent to `NonZeroU16::new(n).unwrap()` +/// +/// FIXME: This can be removed once `Option::unwrap` is stably const. +/// See the `const_option` feature (#67441). +const fn non_zero_u16(n: u16) -> NonZeroU16 { + match NonZeroU16::new(n) { + Some(n) => n, + None => panic!("called `unwrap` on a `None` value"), + } +} + pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 // string so it's safe for `WStrUnits` to use. @@ -58,10 +69,10 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>( lp_cmd_line: Option<WStrUnits<'a>>, exe_name: F, ) -> Vec<OsString> { - const BACKSLASH: NonZeroU16 = NonZeroU16::new(b'\\' as u16).unwrap(); - const QUOTE: NonZeroU16 = NonZeroU16::new(b'"' as u16).unwrap(); - const TAB: NonZeroU16 = NonZeroU16::new(b'\t' as u16).unwrap(); - const SPACE: NonZeroU16 = NonZeroU16::new(b' ' as u16).unwrap(); + const BACKSLASH: NonZeroU16 = non_zero_u16(b'\\' as u16); + const QUOTE: NonZeroU16 = non_zero_u16(b'"' as u16); + const TAB: NonZeroU16 = non_zero_u16(b'\t' as u16); + const SPACE: NonZeroU16 = non_zero_u16(b' ' as u16); let mut ret_val = Vec::new(); // If the cmd line pointer is null or it points to an empty string then diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 5469487df1eed..c7a42ef9a9382 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -326,7 +326,9 @@ union IO_STATUS_BLOCK_union { } impl Default for IO_STATUS_BLOCK_union { fn default() -> Self { - Self { Pointer: ptr::null_mut() } + let mut this = Self { Pointer: ptr::null_mut() }; + this.Status = STATUS_PENDING; + this } } #[repr(C)] @@ -335,6 +337,16 @@ pub struct IO_STATUS_BLOCK { u: IO_STATUS_BLOCK_union, pub Information: usize, } +impl IO_STATUS_BLOCK { + pub fn status(&self) -> NTSTATUS { + // SAFETY: If `self.u.Status` was set then this is obviously safe. + // If `self.u.Pointer` was set then this is the equivalent to converting + // the pointer to an integer, which is also safe. + // Currently the only safe way to construct `IO_STATUS_BLOCK` outside of + // this module is to call the `default` method, which sets the `Status`. + unsafe { self.u.Status } + } +} pub type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "system" fn( dwErrorCode: DWORD, diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 157d8a044d3cd..e9b1006907741 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -13,6 +13,7 @@ use crate::sys::handle::Handle; use crate::sys::time::SystemTime; use crate::sys::{c, cvt}; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::thread; use super::path::maybe_verbatim; use super::to_u16s; @@ -679,7 +680,7 @@ impl<'a> DirBuffIter<'a> { } } impl<'a> Iterator for DirBuffIter<'a> { - type Item = &'a [u16]; + type Item = (&'a [u16], bool); fn next(&mut self) -> Option<Self::Item> { use crate::mem::size_of; let buffer = &self.buffer?[self.cursor..]; @@ -688,14 +689,16 @@ impl<'a> Iterator for DirBuffIter<'a> { // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the // last field (the file name) is unsized. So an offset has to be // used to get the file name slice. - let (name, next_entry) = unsafe { + let (name, is_directory, next_entry) = unsafe { let info = buffer.as_ptr().cast::<c::FILE_ID_BOTH_DIR_INFO>(); let next_entry = (*info).NextEntryOffset as usize; let name = crate::slice::from_raw_parts( (*info).FileName.as_ptr().cast::<u16>(), (*info).FileNameLength as usize / size_of::<u16>(), ); - (name, next_entry) + let is_directory = ((*info).FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) != 0; + + (name, is_directory, next_entry) }; if next_entry == 0 { @@ -708,7 +711,7 @@ impl<'a> Iterator for DirBuffIter<'a> { const DOT: u16 = b'.' as u16; match name { [DOT] | [DOT, DOT] => self.next(), - _ => Some(name), + _ => Some((name, is_directory)), } } } @@ -993,89 +996,92 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); } - let mut delete: fn(&File) -> io::Result<()> = File::posix_delete; - let result = match delete(&file) { - Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => { - match remove_dir_all_recursive(&file, delete) { - // Return unexpected errors. - Err(e) if e.kind() != io::ErrorKind::DirectoryNotEmpty => return Err(e), - result => result, - } - } - // If POSIX delete is not supported for this filesystem then fallback to win32 delete. - Err(e) - if e.raw_os_error() == Some(c::ERROR_NOT_SUPPORTED as i32) - || e.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) => - { - delete = File::win32_delete; - Err(e) - } - result => result, - }; - if result.is_ok() { - Ok(()) - } else { - // This is a fallback to make sure the directory is actually deleted. - // Otherwise this function is prone to failing with `DirectoryNotEmpty` - // due to possible delays between marking a file for deletion and the - // file actually being deleted from the filesystem. - // - // So we retry a few times before giving up. - for _ in 0..5 { - match remove_dir_all_recursive(&file, delete) { - Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {} - result => return result, + + match remove_dir_all_iterative(&file, File::posix_delete) { + Err(e) => { + if let Some(code) = e.raw_os_error() { + match code as u32 { + // If POSIX delete is not supported for this filesystem then fallback to win32 delete. + c::ERROR_NOT_SUPPORTED + | c::ERROR_INVALID_FUNCTION + | c::ERROR_INVALID_PARAMETER => { + remove_dir_all_iterative(&file, File::win32_delete) + } + _ => Err(e), + } + } else { + Err(e) } } - // Try one last time. - delete(&file) + ok => ok, } } -fn remove_dir_all_recursive(f: &File, delete: fn(&File) -> io::Result<()>) -> io::Result<()> { +fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io::Result<()> { + // When deleting files we may loop this many times when certain error conditions occur. + // This allows remove_dir_all to succeed when the error is temporary. + const MAX_RETRIES: u32 = 10; + let mut buffer = DirBuff::new(); - let mut restart = true; - // Fill the buffer and iterate the entries. - while f.fill_dir_buff(&mut buffer, restart)? { - for name in buffer.iter() { - // Open the file without following symlinks and try deleting it. - // We try opening will all needed permissions and if that is denied - // fallback to opening without `FILE_LIST_DIRECTORY` permission. - // Note `SYNCHRONIZE` permission is needed for synchronous access. - let mut result = - open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY); - if matches!(&result, Err(e) if e.kind() == io::ErrorKind::PermissionDenied) { - result = open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE); + let mut dirlist = vec![f.duplicate()?]; + + // FIXME: This is a hack so we can push to the dirlist vec after borrowing from it. + fn copy_handle(f: &File) -> mem::ManuallyDrop<File> { + unsafe { mem::ManuallyDrop::new(File::from_raw_handle(f.as_raw_handle())) } + } + + while let Some(dir) = dirlist.last() { + let dir = copy_handle(dir); + + // Fill the buffer and iterate the entries. + let more_data = dir.fill_dir_buff(&mut buffer, false)?; + for (name, is_directory) in buffer.iter() { + if is_directory { + let child_dir = open_link_no_reparse( + &dir, + name, + c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY, + )?; + dirlist.push(child_dir); + } else { + for i in 1..=MAX_RETRIES { + let result = open_link_no_reparse(&dir, name, c::SYNCHRONIZE | c::DELETE); + match result { + Ok(f) => delete(&f)?, + // Already deleted, so skip. + Err(e) if e.kind() == io::ErrorKind::NotFound => break, + // Retry a few times if the file is locked or a delete is already in progress. + Err(e) + if i < MAX_RETRIES + && (e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) + || e.raw_os_error() + == Some(c::ERROR_SHARING_VIOLATION as _)) => {} + // Otherwise return the error. + Err(e) => return Err(e), + } + thread::yield_now(); + } } - match result { - Ok(file) => match delete(&file) { - Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => { - // Iterate the directory's files. - // Ignore `DirectoryNotEmpty` errors here. They will be - // caught when `remove_dir_all` tries to delete the top - // level directory. It can then decide if to retry or not. - match remove_dir_all_recursive(&file, delete) { - Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {} - result => result?, + } + // If there were no more files then delete the directory. + if !more_data { + if let Some(dir) = dirlist.pop() { + // Retry deleting a few times in case we need to wait for a file to be deleted. + for i in 1..=MAX_RETRIES { + let result = delete(&dir); + if let Err(e) = result { + if i == MAX_RETRIES || e.kind() != io::ErrorKind::DirectoryNotEmpty { + return Err(e); } + thread::yield_now(); + } else { + break; } - result => result?, - }, - // Ignore error if a delete is already in progress or the file - // has already been deleted. It also ignores sharing violations - // (where a file is locked by another process) as these are - // usually temporary. - Err(e) - if e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) - || e.kind() == io::ErrorKind::NotFound - || e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {} - Err(e) => return Err(e), + } } } - // Continue reading directory entries without restarting from the beginning, - restart = false; } - delete(&f) + Ok(()) } pub fn readlink(path: &Path) -> io::Result<PathBuf> { diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 1e7b6e1eab03a..e24b09cc96ec8 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -1,5 +1,8 @@ #![unstable(issue = "none", feature = "windows_handle")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf}; use crate::mem; @@ -248,14 +251,18 @@ impl Handle { offset.map(|n| n as _).as_ref(), None, ); + + let status = if status == c::STATUS_PENDING { + c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE); + io_status.status() + } else { + status + }; match status { // If the operation has not completed then abort the process. // Doing otherwise means that the buffer and stack may be written to // after this function returns. - c::STATUS_PENDING => { - eprintln!("I/O error: operation failed to complete synchronously"); - crate::process::abort(); - } + c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"), // Return `Ok(0)` when there's nothing more to read. c::STATUS_END_OF_FILE => Ok(0), @@ -294,13 +301,17 @@ impl Handle { None, ) }; + let status = if status == c::STATUS_PENDING { + unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) }; + io_status.status() + } else { + status + }; match status { // If the operation has not completed then abort the process. // Doing otherwise means that the buffer may be read and the stack // written to after this function returns. - c::STATUS_PENDING => { - rtabort!("I/O error: operation failed to complete synchronously"); - } + c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"), // Success! status if c::nt_success(status) => Ok(io_status.Information), diff --git a/library/std/src/sys/windows/handle/tests.rs b/library/std/src/sys/windows/handle/tests.rs new file mode 100644 index 0000000000000..d836dae4c305b --- /dev/null +++ b/library/std/src/sys/windows/handle/tests.rs @@ -0,0 +1,22 @@ +use crate::sys::pipe::{anon_pipe, Pipes}; +use crate::{thread, time}; + +/// Test the synchronous fallback for overlapped I/O. +#[test] +fn overlapped_handle_fallback() { + // Create some pipes. `ours` will be asynchronous. + let Pipes { ours, theirs } = anon_pipe(true, false).unwrap(); + + let async_readable = ours.into_handle(); + let sync_writeable = theirs.into_handle(); + + thread::scope(|_| { + thread::sleep(time::Duration::from_millis(100)); + sync_writeable.write(b"hello world!").unwrap(); + }); + + // The pipe buffer starts empty so reading won't complete synchronously unless + // our fallback path works. + let mut buffer = [0u8; 1024]; + async_readable.read(&mut buffer).unwrap(); +} diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 9fd399f4ba1d3..02d5af4719ae8 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -707,6 +707,12 @@ impl From<u8> for ExitCode { } } +impl From<u32> for ExitCode { + fn from(code: u32) -> Self { + ExitCode(c::DWORD::from(code)) + } +} + fn zeroed_startupinfo() -> c::STARTUPINFO { c::STARTUPINFO { cb: 0, diff --git a/library/std/src/sys_common/lazy_box.rs b/library/std/src/sys_common/lazy_box.rs index 647c13d243724..63c3316bdeb28 100644 --- a/library/std/src/sys_common/lazy_box.rs +++ b/library/std/src/sys_common/lazy_box.rs @@ -21,8 +21,21 @@ pub(crate) trait LazyInit { /// /// It might be called more than once per LazyBox, as multiple threads /// might race to initialize it concurrently, each constructing and initializing - /// their own box. (All but one of them will be destroyed right after.) + /// their own box. All but one of them will be passed to `cancel_init` right after. fn init() -> Box<Self>; + + /// Any surplus boxes from `init()` that lost the initialization race + /// are passed to this function for disposal. + /// + /// The default implementation calls destroy(). + fn cancel_init(x: Box<Self>) { + Self::destroy(x); + } + + /// This is called to destroy a used box. + /// + /// The default implementation just drops it. + fn destroy(_: Box<Self>) {} } impl<T: LazyInit> LazyBox<T> { @@ -45,7 +58,7 @@ impl<T: LazyInit> LazyBox<T> { Err(ptr) => { // Lost the race to another thread. // Drop the box we created, and use the one from the other thread instead. - drop(unsafe { Box::from_raw(new_ptr) }); + T::cancel_init(unsafe { Box::from_raw(new_ptr) }); ptr } } @@ -71,7 +84,7 @@ impl<T: LazyInit> Drop for LazyBox<T> { fn drop(&mut self) { let ptr = *self.ptr.get_mut(); if !ptr.is_null() { - drop(unsafe { Box::from_raw(ptr) }); + T::destroy(unsafe { Box::from_raw(ptr) }); } } } diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 7e8bfb2565e45..cbd7832eb7a4c 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -10,9 +10,10 @@ cfg_if::cfg_if! { ))] { mod futex; pub use futex::Parker; - } else if #[cfg(windows)] { - pub use crate::sys::thread_parker::Parker; - } else if #[cfg(target_family = "unix")] { + } else if #[cfg(target_os = "solid_asp3")] { + mod wait_flag; + pub use wait_flag::Parker; + } else if #[cfg(any(windows, target_family = "unix"))] { pub use crate::sys::thread_parker::Parker; } else { mod generic; diff --git a/library/std/src/sys_common/thread_parker/wait_flag.rs b/library/std/src/sys_common/thread_parker/wait_flag.rs new file mode 100644 index 0000000000000..6561c186655a5 --- /dev/null +++ b/library/std/src/sys_common/thread_parker/wait_flag.rs @@ -0,0 +1,102 @@ +//! A wait-flag-based thread parker. +//! +//! Some operating systems provide low-level parking primitives like wait counts, +//! event flags or semaphores which are not susceptible to race conditions (meaning +//! the wakeup can occur before the wait operation). To implement the `std` thread +//! parker on top of these primitives, we only have to ensure that parking is fast +//! when the thread token is available, the atomic ordering guarantees are maintained +//! and spurious wakeups are minimized. +//! +//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`, +//! `PARKED` and `NOTIFIED`: +//! * `EMPTY` means the token has not been made available, but the thread is not +//! currently waiting on it. +//! * `PARKED` means the token is not available and the thread is parked. +//! * `NOTIFIED` means the token is available. +//! +//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from +//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and +//! execution can continue without calling into the OS. If the state was `EMPTY`, +//! the token is not available and the thread waits on the primitive (here called +//! "wait flag"). +//! +//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread +//! is or will be sleeping on the wait flag, so we raise it. + +use crate::pin::Pin; +use crate::sync::atomic::AtomicI8; +use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; +use crate::sys::wait_flag::WaitFlag; +use crate::time::Duration; + +const EMPTY: i8 = 0; +const PARKED: i8 = -1; +const NOTIFIED: i8 = 1; + +pub struct Parker { + state: AtomicI8, + wait_flag: WaitFlag, +} + +impl Parker { + /// Construct a parker for the current thread. The UNIX parker + /// implementation requires this to happen in-place. + pub unsafe fn new(parker: *mut Parker) { + parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() }) + } + + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park(self: Pin<&Self>) { + match self.state.fetch_sub(1, Acquire) { + // NOTIFIED => EMPTY + NOTIFIED => return, + // EMPTY => PARKED + EMPTY => (), + _ => panic!("inconsistent park state"), + } + + // Avoid waking up from spurious wakeups (these are quite likely, see below). + loop { + self.wait_flag.wait(); + + match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) { + Ok(_) => return, + Err(PARKED) => (), + Err(_) => panic!("inconsistent park state"), + } + } + } + + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + match self.state.fetch_sub(1, Acquire) { + NOTIFIED => return, + EMPTY => (), + _ => panic!("inconsistent park state"), + } + + self.wait_flag.wait_timeout(dur); + + // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be + // a race condition when `unpark` is performed between receiving the timeout and + // resetting the state, resulting in the eventflag being set unnecessarily. `park` + // is protected against this by looping until the token is actually given, but + // here we cannot easily tell. + + // Use `swap` to provide acquire ordering. + match self.state.swap(EMPTY, Acquire) { + NOTIFIED => (), + PARKED => (), + _ => panic!("inconsistent park state"), + } + } + + // This implementation doesn't require `Pin`, but other implementations do. + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + + if state == PARKED { + self.wait_flag.raise(); + } + } +} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0a6a7cfe976cc..d28c7b58b20ba 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -159,6 +159,7 @@ use crate::cell::UnsafeCell; use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; +use crate::marker::PhantomData; use crate::mem; use crate::num::NonZeroU64; use crate::num::NonZeroUsize; @@ -462,7 +463,7 @@ impl Builder { unsafe fn spawn_unchecked_<'a, 'scope, F, T>( self, f: F, - scope_data: Option<&'scope scoped::ScopeData>, + scope_data: Option<Arc<scoped::ScopeData>>, ) -> io::Result<JoinInner<'scope, T>> where F: FnOnce() -> T, @@ -479,8 +480,11 @@ impl Builder { })); let their_thread = my_thread.clone(); - let my_packet: Arc<Packet<'scope, T>> = - Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) }); + let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet { + scope: scope_data, + result: UnsafeCell::new(None), + _marker: PhantomData, + }); let their_packet = my_packet.clone(); let output_capture = crate::io::set_output_capture(None); @@ -507,7 +511,7 @@ impl Builder { unsafe { *their_packet.result.get() = Some(try_result) }; }; - if let Some(scope_data) = scope_data { + if let Some(scope_data) = &my_packet.scope { scope_data.increment_num_running_threads(); } @@ -1110,7 +1114,7 @@ impl Thread { // Used only internally to construct a thread object without spawning // Panics if the name contains nuls. pub(crate) fn new(name: Option<CString>) -> Thread { - // We have to use `unsafe` here to constuct the `Parker` in-place, + // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // // SAFETY: We pin the Arc immediately after creation, so its address never @@ -1298,8 +1302,9 @@ pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>; // An Arc to the packet is stored into a `JoinInner` which in turns is placed // in `JoinHandle`. struct Packet<'scope, T> { - scope: Option<&'scope scoped::ScopeData>, + scope: Option<Arc<scoped::ScopeData>>, result: UnsafeCell<Option<Result<T>>>, + _marker: PhantomData<Option<&'scope scoped::ScopeData>>, } // Due to the usage of `UnsafeCell` we need to manually implement Sync. @@ -1330,7 +1335,7 @@ impl<'scope, T> Drop for Packet<'scope, T> { rtabort!("thread result panicked on drop"); } // Book-keeping so the scope knows when it's done. - if let Some(scope) = self.scope { + if let Some(scope) = &self.scope { // Now that there will be no more user code running on this thread // that can use 'scope, mark the thread as 'finished'. // It's important we only do this after the `result` has been dropped, diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index a387a09dc8b15..e6dbf35bd0286 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -11,7 +11,7 @@ use crate::sync::Arc; /// See [`scope`] for details. #[stable(feature = "scoped_threads", since = "1.63.0")] pub struct Scope<'scope, 'env: 'scope> { - data: ScopeData, + data: Arc<ScopeData>, /// Invariance over 'scope, to make sure 'scope cannot shrink, /// which is necessary for soundness. /// @@ -130,12 +130,14 @@ pub fn scope<'env, F, T>(f: F) -> T where F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, { + // We put the `ScopeData` into an `Arc` so that other threads can finish their + // `decrement_num_running_threads` even after this function returns. let scope = Scope { - data: ScopeData { + data: Arc::new(ScopeData { num_running_threads: AtomicUsize::new(0), main_thread: current(), a_thread_panicked: AtomicBool::new(false), - }, + }), env: PhantomData, scope: PhantomData, }; @@ -250,7 +252,7 @@ impl Builder { F: FnOnce() -> T + Send + 'scope, T: Send + 'scope, { - Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?)) + Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(scope.data.clone())) }?)) } } diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index 000f5fa3f5860..f981b9c495476 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -196,6 +196,7 @@ Test Attributes: pub fn parse_opts(args: &[String]) -> Option<OptRes> { // Parse matches. let opts = optgroups(); + let binary = args.get(0).map(|c| &**c).unwrap_or("..."); let args = args.get(1..).unwrap_or(args); let matches = match opts.parse(args) { Ok(m) => m, @@ -205,7 +206,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> { // Check if help was requested. if matches.opt_present("h") { // Show help and do nothing more. - usage(&args[0], &opts); + usage(binary, &opts); return None; } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 52d737de7aef8..4a6ba6e10c334 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] #![feature(link_cfg)] -#![cfg_attr(bootstrap, feature(native_link_modifiers_bundle))] #![feature(staged_api)] #![feature(c_unwind)] #![feature(cfg_target_abi)] diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md index add73ebd44b8c..85afc1f5f6c68 100644 --- a/src/bootstrap/CHANGELOG.md +++ b/src/bootstrap/CHANGELOG.md @@ -7,11 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Changes since the last major version] +- Vendoring is no longer done automatically when building from git sources. To use vendoring, run `cargo vendor` manually, or use the pre-vendored `rustc-src` tarball. - `llvm-libunwind` now accepts `in-tree` (formerly true), `system` or `no` (formerly false) [#77703](https://github.com/rust-lang/rust/pull/77703) - The options `infodir`, `localstatedir`, and `gpg-password-file` are no longer allowed in config.toml. Previously, they were ignored without warning. Note that `infodir` and `localstatedir` are still accepted by `./configure`, with a warning. [#82451](https://github.com/rust-lang/rust/pull/82451) -- Add options for enabling overflow checks, one for std (`overflow-checks-std`) and one for everything else (`overflow-checks`). Both default to false. - Change the names for `dist` commands to match the component they generate. [#90684](https://github.com/rust-lang/rust/pull/90684) - The `build.fast-submodules` option has been removed. Fast submodule checkouts are enabled unconditionally. Automatic submodule handling can still be disabled with `build.submodules = false`. +- Several unsupported `./configure` options have been removed: `optimize`, `parallel-compiler`. These can still be enabled with `--set`, although it isn't recommended. ### Non-breaking changes @@ -19,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558) - If you have Rust already installed, `x.py` will now infer the host target from the default rust toolchain. [#78513](https://github.com/rust-lang/rust/pull/78513) +- Add options for enabling overflow checks, one for std (`overflow-checks-std`) and one for everything else (`overflow-checks`). Both default to false. ## [Version 2] - 2020-09-25 diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock new file mode 100644 index 0000000000000..664ffa1ddd207 --- /dev/null +++ b/src/bootstrap/Cargo.lock @@ -0,0 +1,778 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bootstrap" +version = "0.0.0" +dependencies = [ + "cc", + "cmake", + "fd-lock", + "filetime", + "getopts", + "hex", + "ignore", + "libc", + "num_cpus", + "once_cell", + "opener", + "pretty_assertions", + "serde", + "serde_json", + "sha2", + "sysinfo", + "tar", + "toml", + "walkdir", + "winapi", + "xz2", +] + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fd-lock" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11dcc7e4d79a8c89b9ab4c6f5c30b1fc4a83c420792da3542fd31179ed5f517" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys", +] + +[[package]] +name = "filetime" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "globset" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "ignore" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +dependencies = [ + "crossbeam-utils", + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "io-lifetimes" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lzma-sys" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb4b7c3eddad11d3af9e86c487607d2d2442d185d848575365c4856ba96d619" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "opener" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952" +dependencies = [ + "bstr", + "winapi", +] + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "pretty_assertions" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "rustix" +version = "0.35.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef258c11e17f5c01979a10543a30a4e12faef6aab217a74266e747eefa3aed88" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sysinfo" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2809487b962344ca55d9aea565f9ffbcb6929780802217acc82561f6746770" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + +[[package]] +name = "xz2" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c" +dependencies = [ + "lzma-sys", +] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ed5c59a259522..84f6aaf99c134 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -36,6 +36,7 @@ test = false [dependencies] cmake = "0.1.38" +fd-lock = "3.0.6" filetime = "0.2" num_cpus = "1.0" getopts = "0.2.19" @@ -74,3 +75,11 @@ pretty_assertions = "0.7" [features] build-metrics = ["sysinfo"] + +# We care a lot about bootstrap's compile times, so don't include debuginfo for +# dependencies, only bootstrap itself. +[profile.dev] +debug = 0 +[profile.dev.package] +# Only use debuginfo=1 to further reduce compile times. +bootstrap.debug = 1 diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index 9c41ab69c8be3..9b4861ccd95f4 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,12 +7,28 @@ use std::env; -use bootstrap::{Build, Config, Subcommand, VERSION}; +use bootstrap::{t, Build, Config, Subcommand, VERSION}; fn main() { let args = env::args().skip(1).collect::<Vec<_>>(); let config = Config::parse(&args); + let mut build_lock; + let _build_lock_guard; + if cfg!(any(unix, windows)) { + build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock")))); + _build_lock_guard = match build_lock.try_write() { + Ok(lock) => lock, + err => { + println!("warning: build directory locked, waiting for lock"); + drop(err); + t!(build_lock.write()) + } + }; + } else { + println!("warning: file locking not supported for target, not locking build directory"); + } + // check_version warnings are not printed during setup let changelog_suggestion = if matches!(config.cmd, Subcommand::Setup { .. }) { None } else { check_version(&config) }; diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 5f85fc5aa5903..87c1d22e77146 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -31,9 +31,7 @@ fn main() { let mut cmd = Command::new(rustdoc); - // cfg(bootstrap) - // NOTE: the `--test` special-casing can be removed when https://github.com/rust-lang/cargo/pull/10594 lands on beta. - if target.is_some() || args.iter().any(|x| x == "--test") { + if target.is_some() { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option, // unless one is already set. diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3b2b507b06237..9301c5a2ff300 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -15,44 +15,6 @@ from time import time, sleep -# Acquire a lock on the build directory to make sure that -# we don't cause a race condition while building -# Lock is created in `build_dir/lock.db` -def acquire_lock(build_dir): - try: - import sqlite3 - - path = os.path.join(build_dir, "lock.db") - try: - con = sqlite3.Connection(path, timeout=0) - curs = con.cursor() - curs.execute("BEGIN EXCLUSIVE") - # The lock is released when the cursor is dropped - return curs - # If the database is busy then lock has already been acquired - # so we wait for the lock. - # We retry every quarter second so that execution is passed back to python - # so that it can handle signals - except sqlite3.OperationalError: - del con - del curs - print("Waiting for lock on build directory") - con = sqlite3.Connection(path, timeout=0.25) - curs = con.cursor() - while True: - try: - curs.execute("BEGIN EXCLUSIVE") - break - except sqlite3.OperationalError: - pass - sleep(0.25) - return curs - except ImportError: - print("warning: sqlite3 not available in python, skipping build directory lock") - print("please file an issue on rust-lang/rust") - print("this is not a problem for non-concurrent x.py invocations") - return None - def support_xz(): try: with tempfile.NamedTemporaryFile(delete=False) as temp_file: @@ -190,6 +152,10 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs): if verbose: print("running: " + ' '.join(args)) sys.stdout.flush() + # Ensure that the .exe is used on Windows just in case a Linux ELF has been + # compiled in the same directory. + if os.name == 'nt' and not args[0].endswith('.exe'): + args[0] += '.exe' # Use Popen here instead of call() as it apparently allows powershell on # Windows to not lock up waiting for input presumably. ret = subprocess.Popen(args, **kwargs) @@ -743,7 +709,7 @@ def bootstrap_binary(self): """ return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap") - def build_bootstrap(self): + def build_bootstrap(self, color): """Build bootstrap""" print("Building rustbuild") build_dir = os.path.join(self.build_dir, "bootstrap") @@ -800,6 +766,11 @@ def build_bootstrap(self): if self.get_toml("metrics", "build"): args.append("--features") args.append("build-metrics") + if color == "always": + args.append("--color=always") + elif color == "never": + args.append("--color=never") + run(args, env=env, verbose=self.verbose) def build_triple(self): @@ -813,110 +784,6 @@ def build_triple(self): return config return default_build_triple(self.verbose) - def check_submodule(self, module): - checked_out = subprocess.Popen(["git", "rev-parse", "HEAD"], - cwd=os.path.join(self.rust_root, module), - stdout=subprocess.PIPE) - return checked_out - - def update_submodule(self, module, checked_out, recorded_submodules): - module_path = os.path.join(self.rust_root, module) - - default_encoding = sys.getdefaultencoding() - checked_out = checked_out.communicate()[0].decode(default_encoding).strip() - if recorded_submodules[module] == checked_out: - return - - print("Updating submodule", module) - - run(["git", "submodule", "-q", "sync", module], - cwd=self.rust_root, verbose=self.verbose) - - update_args = ["git", "submodule", "update", "--init", "--recursive", "--depth=1"] - if self.git_version >= distutils.version.LooseVersion("2.11.0"): - update_args.append("--progress") - update_args.append(module) - try: - run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True) - except RuntimeError: - print("Failed updating submodule. This is probably due to uncommitted local changes.") - print('Either stash the changes by running "git stash" within the submodule\'s') - print('directory, reset them by running "git reset --hard", or commit them.') - print("To reset all submodules' changes run", end=" ") - print('"git submodule foreach --recursive git reset --hard".') - raise SystemExit(1) - - run(["git", "reset", "-q", "--hard"], - cwd=module_path, verbose=self.verbose) - run(["git", "clean", "-qdfx"], - cwd=module_path, verbose=self.verbose) - - def update_submodules(self): - """Update submodules""" - has_git = os.path.exists(os.path.join(self.rust_root, ".git")) - # This just arbitrarily checks for cargo, but any workspace member in - # a submodule would work. - has_submodules = os.path.exists(os.path.join(self.rust_root, "src/tools/cargo/Cargo.toml")) - if not has_git and not has_submodules: - print("This is not a git repository, and the requisite git submodules were not found.") - print("If you downloaded the source from https://github.com/rust-lang/rust/releases,") - print("those sources will not work. Instead, consider downloading from the source") - print("releases linked at") - print("https://forge.rust-lang.org/infra/other-installation-methods.html#source-code") - print("or clone the repository at https://github.com/rust-lang/rust/.") - raise SystemExit(1) - if not has_git or self.get_toml('submodules') == "false": - return - - default_encoding = sys.getdefaultencoding() - - # check the existence and version of 'git' command - git_version_str = require(['git', '--version']).split()[2].decode(default_encoding) - self.git_version = distutils.version.LooseVersion(git_version_str) - - start_time = time() - print('Updating only changed submodules') - default_encoding = sys.getdefaultencoding() - # Only update submodules that are needed to build bootstrap. These are needed because Cargo - # currently requires everything in a workspace to be "locally present" when starting a - # build, and will give a hard error if any Cargo.toml files are missing. - # FIXME: Is there a way to avoid cloning these eagerly? Bootstrap itself doesn't need to - # share a workspace with any tools - maybe it could be excluded from the workspace? - # That will still require cloning the submodules the second you check the standard - # library, though... - # FIXME: Is there a way to avoid hard-coding the submodules required? - # WARNING: keep this in sync with the submodules hard-coded in bootstrap/lib.rs - submodules = [ - "src/tools/rust-installer", - "src/tools/cargo", - "src/tools/rls", - "src/tools/miri", - "library/backtrace", - "library/stdarch" - ] - # If build.vendor is set in config.toml, we must update rust-analyzer also. - # Otherwise, the bootstrap will fail (#96456). - if self.use_vendored_sources: - submodules.append("src/tools/rust-analyzer") - filtered_submodules = [] - submodules_names = [] - for module in submodules: - check = self.check_submodule(module) - filtered_submodules.append((module, check)) - submodules_names.append(module) - recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names, - cwd=self.rust_root, stdout=subprocess.PIPE) - recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines() - # { filename: hash } - recorded_submodules = {} - for data in recorded: - # [mode, kind, hash, filename] - data = data.split() - recorded_submodules[data[3]] = data[2] - for module in filtered_submodules: - self.update_submodule(module[0], module[1], recorded_submodules) - print(" Submodules updated in %.2f seconds" % (time() - start_time)) - def set_dist_environment(self, url): """Set download URL for normal environment""" if 'RUSTUP_DIST_SERVER' in os.environ: @@ -926,54 +793,32 @@ def set_dist_environment(self, url): def check_vendored_status(self): """Check that vendoring is configured properly""" - vendor_dir = os.path.join(self.rust_root, 'vendor') if 'SUDO_USER' in os.environ and not self.use_vendored_sources: if os.getuid() == 0: self.use_vendored_sources = True print('info: looks like you\'re trying to run this command as root') print(' and so in order to preserve your $HOME this will now') print(' use vendored sources by default.') - if not os.path.exists(vendor_dir): - print('error: vendoring required, but vendor directory does not exist.') - print(' Run `cargo vendor` without sudo to initialize the ' - 'vendor directory.') - raise Exception("{} not found".format(vendor_dir)) + cargo_dir = os.path.join(self.rust_root, '.cargo') if self.use_vendored_sources: - config = ("[source.crates-io]\n" - "replace-with = 'vendored-sources'\n" - "registry = 'https://example.com'\n" - "\n" - "[source.vendored-sources]\n" - "directory = '{}/vendor'\n" - .format(self.rust_root)) - if not os.path.exists('.cargo'): - os.makedirs('.cargo') - with output('.cargo/config') as cargo_config: - cargo_config.write(config) - else: - print('info: using vendored source, but .cargo/config is already present.') - print(' Reusing the current configuration file. But you may want to ' - 'configure vendoring like this:') - print(config) + vendor_dir = os.path.join(self.rust_root, 'vendor') + if not os.path.exists(vendor_dir): + sync_dirs = "--sync ./src/tools/rust-analyzer/Cargo.toml " \ + "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \ + "--sync ./src/bootstrap/Cargo.toml " + print('error: vendoring required, but vendor directory does not exist.') + print(' Run `cargo vendor {}` to initialize the ' + 'vendor directory.'.format(sync_dirs)) + print('Alternatively, use the pre-vendored `rustc-src` dist component.') + raise Exception("{} not found".format(vendor_dir)) + + if not os.path.exists(cargo_dir): + print('error: vendoring required, but .cargo/config does not exist.') + raise Exception("{} not found".format(cargo_dir)) else: - if os.path.exists('.cargo'): - shutil.rmtree('.cargo') - - def ensure_vendored(self): - """Ensure that the vendored sources are available if needed""" - vendor_dir = os.path.join(self.rust_root, 'vendor') - # Note that this does not handle updating the vendored dependencies if - # the rust git repository is updated. Normal development usually does - # not use vendoring, so hopefully this isn't too much of a problem. - if self.use_vendored_sources and not os.path.exists(vendor_dir): - run([ - self.cargo(), - "vendor", - "--sync=./src/tools/rust-analyzer/Cargo.toml", - "--sync=./compiler/rustc_codegen_cranelift/Cargo.toml", - ], verbose=self.verbose, cwd=self.rust_root) - + if os.path.exists(cargo_dir): + shutil.rmtree(cargo_dir) def bootstrap(help_triggered): """Configure, fetch, build and run the initial bootstrap""" @@ -987,7 +832,9 @@ def bootstrap(help_triggered): parser = argparse.ArgumentParser(description='Build rust') parser.add_argument('--config') + parser.add_argument('--build-dir') parser.add_argument('--build') + parser.add_argument('--color', choices=['always', 'never', 'auto']) parser.add_argument('--clean', action='store_true') parser.add_argument('-v', '--verbose', action='count', default=0) @@ -1035,7 +882,7 @@ def bootstrap(help_triggered): build.check_vendored_status() - build_dir = build.get_toml('build-dir', 'build') or 'build' + build_dir = args.build_dir or build.get_toml('build-dir', 'build') or 'build' build.build_dir = os.path.abspath(build_dir) with open(os.path.join(build.rust_root, "src", "stage0.json")) as f: @@ -1047,18 +894,13 @@ def bootstrap(help_triggered): build.build = args.build or build.build_triple() - # Acquire the lock before doing any build actions - # The lock is released when `lock` is dropped if not os.path.exists(build.build_dir): os.makedirs(build.build_dir) - lock = acquire_lock(build.build_dir) - build.update_submodules() # Fetch/build the bootstrap build.download_toolchain() sys.stdout.flush() - build.ensure_vendored() - build.build_bootstrap() + build.build_bootstrap(args.color) sys.stdout.flush() # Run the bootstrap diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 62b5416cee8af..1aa79f5566aa6 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -13,7 +13,6 @@ use std::process::{Command, Stdio}; use std::time::{Duration, Instant}; use crate::cache::{Cache, Interned, INTERNER}; -use crate::compile; use crate::config::{SplitDebuginfo, TargetSelection}; use crate::dist; use crate::doc; @@ -26,6 +25,7 @@ use crate::tool::{self, SourceType}; use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t}; use crate::EXTRA_CHECK_CFGS; use crate::{check, Config}; +use crate::{compile, Crate}; use crate::{Build, CLang, DocTests, GitRepo, Mode}; pub use crate::Compiler; @@ -304,9 +304,7 @@ impl StepDescription { if paths.is_empty() || builder.config.include_default_paths { for (desc, should_run) in v.iter().zip(&should_runs) { if desc.default && should_run.is_really_default() { - for pathset in &should_run.paths { - desc.maybe_run(builder, vec![pathset.clone()]); - } + desc.maybe_run(builder, should_run.paths.iter().cloned().collect()); } } } @@ -348,11 +346,7 @@ impl StepDescription { eprintln!( "note: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`" ); - #[cfg(not(test))] - std::process::exit(1); - #[cfg(test)] - // so we can use #[should_panic] - panic!() + crate::detail_exit(1); } } } @@ -424,8 +418,16 @@ impl<'a> ShouldRun<'a> { /// any of its (local) dependencies. /// /// `make_run` will be called a single time with all matching command-line paths. - pub fn krate(mut self, name: &str) -> Self { - for krate in self.builder.in_tree_crates(name, None) { + pub fn crate_or_deps(self, name: &str) -> Self { + let crates = self.builder.in_tree_crates(name, None); + self.crates(crates) + } + + /// Indicates it should run if the command-line selects any of the given crates. + /// + /// `make_run` will be called a single time with all matching command-line paths. + pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self { + for krate in crates { let path = krate.local_path(self.builder); self.paths.insert(PathSet::one(path, self.kind)); } @@ -581,6 +583,7 @@ impl<'a> Builder<'a> { match kind { Kind::Build => describe!( compile::Std, + compile::Rustc, compile::Assemble, compile::CodegenBackend, compile::StartupObjects, @@ -694,6 +697,8 @@ impl<'a> Builder<'a> { doc::RustcBook, doc::CargoBook, doc::Clippy, + doc::ClippyBook, + doc::Miri, doc::EmbeddedBook, doc::EditionGuide, ), @@ -945,6 +950,7 @@ impl<'a> Builder<'a> { } pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_error: &str) { + self.verbose(&format!("download {url}")); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. let tempfile = self.tempdir().join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might @@ -1000,7 +1006,7 @@ impl<'a> Builder<'a> { if !help_on_error.is_empty() { eprintln!("{}", help_on_error); } - std::process::exit(1); + crate::detail_exit(1); } } @@ -1429,7 +1435,7 @@ impl<'a> Builder<'a> { "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component" ); eprintln!("help: try `rustup component add clippy`"); - std::process::exit(1); + crate::detail_exit(1); }); if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") { rustflags.arg("--cfg=bootstrap"); @@ -1758,9 +1764,11 @@ impl<'a> Builder<'a> { if !target.contains("windows") { let needs_unstable_opts = target.contains("linux") + || target.contains("solaris") || target.contains("windows") || target.contains("bsd") - || target.contains("dragonfly"); + || target.contains("dragonfly") + || target.contains("illumos"); if needs_unstable_opts { rustflags.arg("-Zunstable-options"); diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 70cb0de7cce04..c084e77d3a994 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -57,6 +57,24 @@ fn check_cli<const N: usize>(paths: [&str; N]) { ); } +macro_rules! std { + ($host:ident => $target:ident, stage = $stage:literal) => { + compile::Std::new( + Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage }, + TargetSelection::from_user(stringify!($target)), + ) + }; +} + +macro_rules! rustc { + ($host:ident => $target:ident, stage = $stage:literal) => { + compile::Rustc::new( + Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage }, + TargetSelection::from_user(stringify!($target)), + ) + }; +} + #[test] fn test_valid() { // make sure multi suite paths are accepted @@ -117,6 +135,17 @@ fn test_exclude_kind() { assert!(run_build(&[path], config).contains::<tool::CargoTest>()); } +/// Ensure that if someone passes both a single crate and `library`, all library crates get built. +#[test] +fn alias_and_path_for_library() { + let mut cache = + run_build(&["library".into(), "core".into()], configure("build", &["A"], &["A"])); + assert_eq!( + first(cache.all::<compile::Std>()), + &[std!(A => A, stage = 0), std!(A => A, stage = 1)] + ); +} + mod defaults { use super::{configure, first, run_build}; use crate::builder::*; @@ -130,10 +159,7 @@ mod defaults { let a = TargetSelection::from_user("A"); assert_eq!( first(cache.all::<compile::Std>()), - &[ - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - ] + &[std!(A => A, stage = 0), std!(A => A, stage = 1),] ); assert!(!cache.all::<compile::Assemble>().is_empty()); // Make sure rustdoc is only built once. @@ -143,10 +169,7 @@ mod defaults { // - this is the compiler it's _linked_ to, not built with. &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }], ); - assert_eq!( - first(cache.all::<compile::Rustc>()), - &[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },] - ); + assert_eq!(first(cache.all::<compile::Rustc>()), &[rustc!(A => A, stage = 0)],); } #[test] @@ -155,10 +178,7 @@ mod defaults { let mut cache = run_build(&[], config); let a = TargetSelection::from_user("A"); - assert_eq!( - first(cache.all::<compile::Std>()), - &[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },] - ); + assert_eq!(first(cache.all::<compile::Std>()), &[std!(A => A, stage = 0)]); assert!(!cache.all::<compile::Assemble>().is_empty()); assert_eq!( first(cache.all::<tool::Rustdoc>()), @@ -185,10 +205,10 @@ mod defaults { assert_eq!( first(cache.all::<compile::Std>()), &[ - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => B, stage = 0), + std!(A => B, stage = 1), ] ); assert_eq!( @@ -208,10 +228,7 @@ mod defaults { ); assert_eq!( first(cache.all::<compile::Rustc>()), - &[ - compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, - ] + &[rustc!(A => A, stage = 0), rustc!(A => B, stage = 0),] ); } @@ -334,11 +351,11 @@ mod dist { assert_eq!( first(cache.all::<compile::Std>()), &[ - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => A, stage = 2), + std!(A => B, stage = 1), + std!(A => B, stage = 2), ], ); assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]); @@ -346,7 +363,6 @@ mod dist { #[test] fn dist_only_cross_host() { - let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); let mut config = configure(&["A", "B"], &["A", "B"]); config.docs = false; @@ -360,10 +376,7 @@ mod dist { ); assert_eq!( first(cache.all::<compile::Rustc>()), - &[ - compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, - ] + &[rustc!(A => A, stage = 0), rustc!(A => B, stage = 1),] ); } @@ -450,11 +463,11 @@ mod dist { assert_eq!( first(cache.all::<compile::Std>()), &[ - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => A, stage = 2), + std!(A => B, stage = 1), + std!(A => B, stage = 2), ] ); assert_eq!( @@ -474,33 +487,29 @@ mod dist { let mut builder = Builder::new(&build); builder.run_step_descriptions( &Builder::get_step_descriptions(Kind::Build), - &["compiler/rustc".into(), "library/std".into()], + &["compiler/rustc".into(), "library".into()], ); - let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); - let c = TargetSelection::from_user("C"); - assert_eq!( first(builder.cache.all::<compile::Std>()), &[ - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, + std!(A => A, stage = 0), + std!(A => A, stage = 1), + std!(A => A, stage = 2), + std!(A => B, stage = 1), + std!(A => B, stage = 2), + std!(A => C, stage = 2), ] ); - assert!(!builder.cache.all::<compile::Assemble>().is_empty()); + assert_eq!(builder.cache.all::<compile::Assemble>().len(), 5); assert_eq!( first(builder.cache.all::<compile::Rustc>()), &[ - compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, - compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b }, + rustc!(A => A, stage = 0), + rustc!(A => A, stage = 1), + rustc!(A => A, stage = 2), + rustc!(A => B, stage = 1), + rustc!(A => B, stage = 2), ] ); } @@ -513,15 +522,10 @@ mod dist { builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); let a = TargetSelection::from_user("A"); - let c = TargetSelection::from_user("C"); assert_eq!( first(builder.cache.all::<compile::Std>()), - &[ - compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - ] + &[std!(A => A, stage = 0), std!(A => A, stage = 1), std!(A => C, stage = 2),] ); assert_eq!( first(builder.cache.all::<compile::Assemble>()), @@ -533,10 +537,7 @@ mod dist { ); assert_eq!( first(builder.cache.all::<compile::Rustc>()), - &[ - compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, - ] + &[rustc!(A => A, stage = 0), rustc!(A => A, stage = 1),] ); } diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 97f0bfdc484da..be5c9bb078808 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -4,13 +4,12 @@ use std::cell::RefCell; use std::cmp::{Ord, Ordering, PartialOrd}; use std::collections::HashMap; use std::convert::AsRef; -use std::ffi::OsStr; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use std::ops::Deref; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::Mutex; // FIXME: replace with std::lazy after it gets stabilized and reaches beta @@ -20,15 +19,9 @@ use crate::builder::Step; pub struct Interned<T>(usize, PhantomData<*const T>); -impl Default for Interned<String> { +impl<T: Internable + Default> Default for Interned<T> { fn default() -> Self { - INTERNER.intern_string(String::default()) - } -} - -impl Default for Interned<PathBuf> { - fn default() -> Self { - INTERNER.intern_path(PathBuf::default()) + T::default().intern() } } @@ -77,87 +70,48 @@ impl fmt::Display for Interned<String> { } } -impl fmt::Debug for Interned<String> { +impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T> +where + Self: Deref<Target = U>, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s: &str = &*self; - f.write_fmt(format_args!("{:?}", s)) - } -} -impl fmt::Debug for Interned<PathBuf> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s: &Path = &*self; + let s: &U = &*self; f.write_fmt(format_args!("{:?}", s)) } } -impl Hash for Interned<String> { +impl<T: Internable + Hash> Hash for Interned<T> { fn hash<H: Hasher>(&self, state: &mut H) { - let l = INTERNER.strs.lock().unwrap(); + let l = T::intern_cache().lock().unwrap(); l.get(*self).hash(state) } } -impl Hash for Interned<PathBuf> { - fn hash<H: Hasher>(&self, state: &mut H) { - let l = INTERNER.paths.lock().unwrap(); - l.get(*self).hash(state) +impl<T: Internable + Deref> Deref for Interned<T> { + type Target = T::Target; + fn deref(&self) -> &'static Self::Target { + let l = T::intern_cache().lock().unwrap(); + unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) } } } -impl Deref for Interned<String> { - type Target = str; - fn deref(&self) -> &'static str { - let l = INTERNER.strs.lock().unwrap(); - unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) } +impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> { + fn as_ref(&self) -> &'static U { + let l = T::intern_cache().lock().unwrap(); + unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) } } } -impl Deref for Interned<PathBuf> { - type Target = Path; - fn deref(&self) -> &'static Path { - let l = INTERNER.paths.lock().unwrap(); - unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) } - } -} - -impl AsRef<Path> for Interned<PathBuf> { - fn as_ref(&self) -> &'static Path { - let l = INTERNER.paths.lock().unwrap(); - unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) } - } -} - -impl AsRef<Path> for Interned<String> { - fn as_ref(&self) -> &'static Path { - let l = INTERNER.strs.lock().unwrap(); - unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) } - } -} - -impl AsRef<OsStr> for Interned<PathBuf> { - fn as_ref(&self) -> &'static OsStr { - let l = INTERNER.paths.lock().unwrap(); - unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) } - } -} - -impl AsRef<OsStr> for Interned<String> { - fn as_ref(&self) -> &'static OsStr { - let l = INTERNER.strs.lock().unwrap(); - unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) } - } -} - -impl PartialOrd<Interned<String>> for Interned<String> { +impl<T: Internable + PartialOrd> PartialOrd for Interned<T> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - let l = INTERNER.strs.lock().unwrap(); + let l = T::intern_cache().lock().unwrap(); l.get(*self).partial_cmp(l.get(*other)) } } -impl Ord for Interned<String> { +impl<T: Internable + Ord> Ord for Interned<T> { fn cmp(&self, other: &Self) -> Ordering { - let l = INTERNER.strs.lock().unwrap(); + let l = T::intern_cache().lock().unwrap(); l.get(*self).cmp(l.get(*other)) } } @@ -208,6 +162,33 @@ impl<T: Hash + Clone + Eq> TyIntern<T> { pub struct Interner { strs: Mutex<TyIntern<String>>, paths: Mutex<TyIntern<PathBuf>>, + lists: Mutex<TyIntern<Vec<String>>>, +} + +trait Internable: Clone + Eq + Hash + 'static { + fn intern_cache() -> &'static Mutex<TyIntern<Self>>; + + fn intern(self) -> Interned<Self> { + Self::intern_cache().lock().unwrap().intern(self) + } +} + +impl Internable for String { + fn intern_cache() -> &'static Mutex<TyIntern<Self>> { + &INTERNER.strs + } +} + +impl Internable for PathBuf { + fn intern_cache() -> &'static Mutex<TyIntern<Self>> { + &INTERNER.paths + } +} + +impl Internable for Vec<String> { + fn intern_cache() -> &'static Mutex<TyIntern<Self>> { + &INTERNER.lists + } } impl Interner { @@ -221,6 +202,10 @@ impl Interner { pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> { self.paths.lock().unwrap().intern(s) } + + pub fn intern_list(&self, v: Vec<String>) -> Interned<Vec<String>> { + self.lists.lock().unwrap().intern(v) + } } pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default); diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index dca782c29c252..759a99c330c27 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -61,6 +61,30 @@ fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> { } } +fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { + let mut cfg = cc::Build::new(); + cfg.cargo_metadata(false) + .opt_level(2) + .warnings(false) + .debug(false) + .target(&target.triple) + .host(&build.build.triple); + match build.crt_static(target) { + Some(a) => { + cfg.static_crt(a); + } + None => { + if target.contains("msvc") { + cfg.static_crt(true); + } + if target.contains("musl") { + cfg.static_flag(true); + } + } + } + cfg +} + pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. @@ -72,27 +96,7 @@ pub fn find(build: &mut Build) { .chain(iter::once(build.build)) .collect::<HashSet<_>>(); for target in targets.into_iter() { - let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false) - .opt_level(2) - .warnings(false) - .debug(false) - .target(&target.triple) - .host(&build.build.triple); - match build.crt_static(target) { - Some(a) => { - cfg.static_crt(a); - } - None => { - if target.contains("msvc") { - cfg.static_crt(true); - } - if target.contains("musl") { - cfg.static_flag(true); - } - } - } - + let mut cfg = new_cc_build(build, target); let config = build.config.target_config.get(&target); if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { cfg.compiler(cc); @@ -112,15 +116,8 @@ pub fn find(build: &mut Build) { // If we use llvm-libunwind, we will need a C++ compiler as well for all targets // We'll need one anyways if the target triple is also a host triple - let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false) - .opt_level(2) - .warnings(false) - .debug(false) - .cpp(true) - .target(&target.triple) - .host(&build.build.triple); - + let mut cfg = new_cc_build(build, target); + cfg.cpp(true); let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); true diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 731ebc41bb9a0..9196b78c513fe 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -20,7 +20,15 @@ fn args(builder: &Builder<'_>) -> Vec<String> { arr.iter().copied().map(String::from) } - if let Subcommand::Clippy { fix, .. } = builder.config.cmd { + if let Subcommand::Clippy { + fix, + clippy_lint_allow, + clippy_lint_deny, + clippy_lint_warn, + clippy_lint_forbid, + .. + } = &builder.config.cmd + { // disable the most spammy clippy lints let ignored_lints = vec![ "many_single_char_names", // there are a lot in stdarch @@ -32,7 +40,7 @@ fn args(builder: &Builder<'_>) -> Vec<String> { "wrong_self_convention", ]; let mut args = vec![]; - if fix { + if *fix { #[rustfmt::skip] args.extend(strings(&[ "--fix", "-Zunstable-options", @@ -44,6 +52,12 @@ fn args(builder: &Builder<'_>) -> Vec<String> { } args.extend(strings(&["--", "--cap-lints", "warn"])); args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint))); + let mut clippy_lint_levels: Vec<String> = Vec::new(); + clippy_lint_allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v))); + clippy_lint_deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v))); + clippy_lint_warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v))); + clippy_lint_forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v))); + args.extend(clippy_lint_levels); args } else { vec![] @@ -184,8 +198,8 @@ impl Step for Rustc { // the sysroot for the compiler to find. Otherwise, we're going to // fail when building crates that need to generate code (e.g., build // scripts and their dependencies). - builder.ensure(crate::compile::Std { target: compiler.host, compiler }); - builder.ensure(crate::compile::Std { target, compiler }); + builder.ensure(crate::compile::Std::new(compiler, compiler.host)); + builder.ensure(crate::compile::Std::new(compiler, target)); } else { builder.ensure(Std { target }); } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index b4807d1ab3af2..3d678b2290d1c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -13,7 +13,7 @@ use std::fs; use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; -use std::process::{exit, Command, Stdio}; +use std::process::{Command, Stdio}; use std::str; use serde::Deserialize; @@ -25,14 +25,36 @@ use crate::config::{LlvmLibunwind, TargetSelection}; use crate::dist; use crate::native; use crate::tool::SourceType; +use crate::util::get_clang_cl_resource_dir; use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date}; use crate::LLVM_TOOLS; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; -#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { pub target: TargetSelection, pub compiler: Compiler, + /// Whether to build only a subset of crates in the standard library. + /// + /// This shouldn't be used from other steps; see the comment on [`Rustc`]. + crates: Interned<Vec<String>>, +} + +impl Std { + pub fn new(compiler: Compiler, target: TargetSelection) -> Self { + Self { target, compiler, crates: Default::default() } + } +} + +/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation. +fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> { + let mut crates = Vec::new(); + for krate in &run.paths { + let path = krate.assert_single_path(); + let crate_name = run.builder.crate_paths[&path.path]; + crates.push(format!("-p={crate_name}")); + } + INTERNER.intern_list(crates) } impl Step for Std { @@ -43,15 +65,22 @@ impl Step for Std { // When downloading stage1, the standard library has already been copied to the sysroot, so // there's no need to rebuild it. let builder = run.builder; - run.all_krates("test") + run.crate_or_deps("test") .path("library") .lazy_default_condition(Box::new(|| !builder.download_rustc())) } fn make_run(run: RunConfig<'_>) { + // Normally, people will pass *just* library if they pass it. + // But it's possible (although strange) to pass something like `library std core`. + // Build all crates anyway, as if they hadn't passed the other args. + let has_library = + run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); + let crates = if has_library { Default::default() } else { build_crates_in_set(&run) }; run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, + crates, }); } @@ -76,7 +105,7 @@ impl Step for Std { || builder.config.keep_stage_std.contains(&compiler.stage) { builder.info("Warning: Using a potentially old libstd. This may not behave well."); - builder.ensure(StdLink { compiler, target_compiler: compiler, target }); + builder.ensure(StdLink::from_std(self, compiler)); return; } @@ -86,7 +115,7 @@ impl Step for Std { let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); if compiler_to_use != compiler { - builder.ensure(Std { compiler: compiler_to_use, target }); + builder.ensure(Std::new(compiler_to_use, target)); builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target)); // Even if we're not building std this stage, the new sysroot must @@ -94,11 +123,7 @@ impl Step for Std { copy_third_party_objects(builder, &compiler, target); copy_self_contained_objects(builder, &compiler, target); - builder.ensure(StdLink { - compiler: compiler_to_use, - target_compiler: compiler, - target, - }); + builder.ensure(StdLink::from_std(self, compiler_to_use)); return; } @@ -115,17 +140,16 @@ impl Step for Std { run_cargo( builder, cargo, - vec![], + self.crates.to_vec(), &libstd_stamp(builder, compiler, target), target_deps, false, ); - builder.ensure(StdLink { - compiler: builder.compiler(compiler.stage, builder.config.build), - target_compiler: compiler, - target, - }); + builder.ensure(StdLink::from_std( + self, + builder.compiler(compiler.stage, builder.config.build), + )); } } @@ -366,6 +390,19 @@ struct StdLink { pub compiler: Compiler, pub target_compiler: Compiler, pub target: TargetSelection, + /// Not actually used; only present to make sure the cache invalidation is correct. + crates: Interned<Vec<String>>, +} + +impl StdLink { + fn from_std(std: Std, host_compiler: Compiler) -> Self { + Self { + compiler: host_compiler, + target_compiler: std.compiler, + target: std.target, + crates: std.crates, + } + } } impl Step for StdLink { @@ -524,6 +561,18 @@ impl Step for StartupObjects { pub struct Rustc { pub target: TargetSelection, pub compiler: Compiler, + /// Whether to build a subset of crates, rather than the whole compiler. + /// + /// This should only be requested by the user, not used within rustbuild itself. + /// Using it within rustbuild can lead to confusing situation where lints are replayed + /// in two different steps. + crates: Interned<Vec<String>>, +} + +impl Rustc { + pub fn new(compiler: Compiler, target: TargetSelection) -> Self { + Self { target, compiler, crates: Default::default() } + } } impl Step for Rustc { @@ -532,13 +581,22 @@ impl Step for Rustc { const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() + let mut crates = run.builder.in_tree_crates("rustc-main", None); + for (i, krate) in crates.iter().enumerate() { + if krate.name == "rustc-main" { + crates.swap_remove(i); + break; + } + } + run.crates(crates) } fn make_run(run: RunConfig<'_>) { + let crates = build_crates_in_set(&run); run.builder.ensure(Rustc { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, + crates, }); } @@ -560,33 +618,29 @@ impl Step for Rustc { return; } - builder.ensure(Std { compiler, target }); + builder.ensure(Std::new(compiler, target)); if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); - builder.ensure(RustcLink { compiler, target_compiler: compiler, target }); + builder.ensure(RustcLink::from_rustc(self, compiler)); return; } let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); if compiler_to_use != compiler { - builder.ensure(Rustc { compiler: compiler_to_use, target }); + builder.ensure(Rustc::new(compiler_to_use, target)); builder .info(&format!("Uplifting stage1 rustc ({} -> {})", builder.config.build, target)); - builder.ensure(RustcLink { - compiler: compiler_to_use, - target_compiler: compiler, - target, - }); + builder.ensure(RustcLink::from_rustc(self, compiler_to_use)); return; } // Ensure that build scripts and proc macros have a std / libproc_macro to link against. - builder.ensure(Std { - compiler: builder.compiler(self.compiler.stage, builder.config.build), - target: builder.config.build, - }); + builder.ensure(Std::new( + builder.compiler(self.compiler.stage, builder.config.build), + builder.config.build, + )); let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build"); rustc_cargo(builder, &mut cargo, target); @@ -633,17 +687,16 @@ impl Step for Rustc { run_cargo( builder, cargo, - vec![], + self.crates.to_vec(), &librustc_stamp(builder, compiler, target), vec![], false, ); - builder.ensure(RustcLink { - compiler: builder.compiler(compiler.stage, builder.config.build), - target_compiler: compiler, - target, - }); + builder.ensure(RustcLink::from_rustc( + self, + builder.compiler(compiler.stage, builder.config.build), + )); } } @@ -720,10 +773,38 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); } - // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm. + + // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script + // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by + // whitespace. + // + // For example: + // - on windows, when `clang-cl` is used with instrumentation, we need to manually add + // clang's runtime library resource directory so that the profiler runtime library can be + // found. This is to avoid the linker errors about undefined references to + // `__llvm_profile_instrument_memop` when linking `rustc_driver`. + let mut llvm_linker_flags = String::new(); + if builder.config.llvm_profile_generate && target.contains("msvc") { + if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { + // Add clang's runtime library directory to the search path + let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); + } + } + + // The config can also specify its own llvm linker flags. if let Some(ref s) = builder.config.llvm_ldflags { - cargo.env("LLVM_LINKER_FLAGS", s); + if !llvm_linker_flags.is_empty() { + llvm_linker_flags.push_str(" "); + } + llvm_linker_flags.push_str(s); + } + + // Set the linker flags via the env var that `rustc_llvm`'s build script will read. + if !llvm_linker_flags.is_empty() { + cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags); } + // Building with a static libstdc++ is only supported on linux right now, // not for MSVC or macOS if builder.config.llvm_static_stdcpp @@ -758,6 +839,19 @@ struct RustcLink { pub compiler: Compiler, pub target_compiler: Compiler, pub target: TargetSelection, + /// Not actually used; only present to make sure the cache invalidation is correct. + crates: Interned<Vec<String>>, +} + +impl RustcLink { + fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self { + Self { + compiler: host_compiler, + target_compiler: rustc.compiler, + target: rustc.target, + crates: rustc.crates, + } + } } impl Step for RustcLink { @@ -821,7 +915,7 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - builder.ensure(Rustc { compiler, target }); + builder.ensure(Rustc::new(compiler, target)); if builder.config.keep_stage.contains(&compiler.stage) { builder.info( @@ -1103,7 +1197,7 @@ impl Step for Assemble { // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host }); + builder.ensure(Rustc::new(build_compiler, target_compiler.host)); for &backend in builder.config.rust_codegen_backends.iter() { if backend == "llvm" { @@ -1328,7 +1422,7 @@ pub fn run_cargo( }); if !ok { - exit(1); + crate::detail_exit(1); } // Ok now we need to actually find all the files listed in `toplevel`. We've diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 14607741932ea..ea0f78e2a6be9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -11,7 +11,7 @@ use std::ffi::OsStr; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; -use std::process::{exit, Command}; +use std::process::Command; use std::str::FromStr; use crate::builder::{Builder, TaskPath}; @@ -226,6 +226,7 @@ pub struct Stage0Config { pub artifacts_server: String, pub artifacts_with_llvm_assertions_server: String, pub git_merge_commit_email: String, + pub nightly_branch: String, } #[derive(Default, Deserialize)] #[cfg_attr(test, derive(Clone))] @@ -410,7 +411,7 @@ pub struct Target { impl Target { pub fn from_triple(triple: &str) -> Self { let mut target: Self = Default::default(); - if triple.contains("-none") || triple.contains("nvptx") { + if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { target.no_std = true; } target @@ -805,8 +806,6 @@ impl Config { let get_toml = |_| TomlConfig::default(); #[cfg(not(test))] let get_toml = |file: &Path| { - use std::process; - let contents = t!(fs::read_to_string(file), format!("config file {} not found", file.display())); // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of @@ -817,7 +816,7 @@ impl Config { Ok(table) => table, Err(err) => { eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err); - process::exit(2); + crate::detail_exit(2); } } }; @@ -857,7 +856,7 @@ impl Config { let build = toml.build.unwrap_or_default(); set(&mut config.initial_rustc, build.rustc.map(PathBuf::from)); - set(&mut config.out, build.build_dir.map(PathBuf::from)); + set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from))); // NOTE: Bootstrap spawns various commands with different working directories. // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. if !config.out.is_absolute() { @@ -1128,11 +1127,7 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use); config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate); - config.download_rustc_commit = download_ci_rustc_commit( - &config.stage0_metadata, - rust.download_rustc, - config.verbose > 0, - ); + config.download_rustc_commit = download_ci_rustc_commit(&config, rust.download_rustc); } else { config.rust_profile_use = flags.rust_profile_use; config.rust_profile_generate = flags.rust_profile_generate; @@ -1304,6 +1299,15 @@ impl Config { config } + /// A git invocation which runs inside the source directory. + /// + /// Use this rather than `Command::new("git")` in order to support out-of-tree builds. + pub(crate) fn git(&self) -> Command { + let mut git = Command::new("git"); + git.current_dir(&self.src); + git + } + /// Try to find the relative path of `bindir`, otherwise return it in full. pub fn bindir_relative(&self) -> &Path { let bindir = &self.bindir; @@ -1453,9 +1457,8 @@ fn threads_from_config(v: u32) -> u32 { /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. fn download_ci_rustc_commit( - stage0_metadata: &Stage0Metadata, + config: &Config, download_rustc: Option<StringOrBool>, - verbose: bool, ) -> Option<String> { // If `download-rustc` is not set, default to rebuilding. let if_unchanged = match download_rustc { @@ -1468,7 +1471,7 @@ fn download_ci_rustc_commit( }; // Handle running from a directory other than the top level - let top_level = output(Command::new("git").args(&["rev-parse", "--show-toplevel"])); + let top_level = output(config.git().args(&["rev-parse", "--show-toplevel"])); let top_level = top_level.trim_end(); let compiler = format!("{top_level}/compiler/"); let library = format!("{top_level}/library/"); @@ -1476,9 +1479,10 @@ fn download_ci_rustc_commit( // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - Command::new("git") + config + .git() .arg("rev-list") - .arg(format!("--author={}", stage0_metadata.config.git_merge_commit_email)) + .arg(format!("--author={}", config.stage0_metadata.config.git_merge_commit_email)) .args(&["-n1", "--first-parent", "HEAD"]), ); let commit = merge_base.trim_end(); @@ -1487,17 +1491,18 @@ fn download_ci_rustc_commit( println!("help: maybe your repository history is too shallow?"); println!("help: consider disabling `download-rustc`"); println!("help: or fetch enough history to include one upstream commit"); - exit(1); + crate::detail_exit(1); } // Warn if there were changes to the compiler or standard library since the ancestor commit. - let has_changes = !t!(Command::new("git") + let has_changes = !t!(config + .git() .args(&["diff-index", "--quiet", &commit, "--", &compiler, &library]) .status()) .success(); if has_changes { if if_unchanged { - if verbose { + if config.verbose > 0 { println!( "warning: saw changes to compiler/ or library/ since {commit}; \ ignoring `download-rustc`" @@ -1560,7 +1565,7 @@ fn download_ci_rustc(builder: &Builder<'_>, commit: &str) { builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc")); builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc")); let lib_dir = bin_root.join("lib"); - for lib in t!(fs::read_dir(lib_dir)) { + for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if lib.path().extension() == Some(OsStr::new("so")) { builder.fix_bin_or_dylib(&lib.path()); @@ -1636,6 +1641,7 @@ fn download_component( } Some(sha256) } else if tarball.exists() { + builder.unpack(&tarball, &bin_root, prefix); return; } else { None diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 2fc036082cba6..6b139decb5551 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -31,11 +31,10 @@ def v(*args): options.append(Option(*args, value=True)) -o("debug", "rust.debug", "enables debugging environment; does not affect optimization of bootstrapped code (use `--disable-optimize` for that)") +o("debug", "rust.debug", "enables debugging environment; does not affect optimization of bootstrapped code") o("docs", "build.docs", "build standard library documentation") o("compiler-docs", "build.compiler-docs", "build compiler documentation") o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") -o("parallel-compiler", "rust.parallel-compiler", "build a multi-threaded rustc") o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests") o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds") o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds") @@ -70,7 +69,6 @@ def v(*args): # Optimization and debugging options. These may be overridden by the release # channel, etc. -o("optimize", "rust.optimize", "build optimized rust code") o("optimize-llvm", "llvm.optimize", "build optimized LLVM") o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface") @@ -161,7 +159,7 @@ def v(*args): # Many of these are saved below during the "writing configuration" step # (others are conditionally saved). o("manage-submodules", "build.submodules", "let the build manage the git submodules") -o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two") +o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two (not recommended except for testing reproducible builds)") o("extended", "build.extended", "build an extended rust tool set") v("tools", None, "List of extended tools will be installed") @@ -493,4 +491,3 @@ def configure_section(lines, config): p("") p("run `python {}/x.py --help`".format(rust_dir)) -p("") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b1fae356d8931..cba013b5bb689 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -39,7 +39,11 @@ fn missing_tool(tool_name: &str, skip: bool) { if skip { println!("Unable to build {}, skipping dist", tool_name) } else { - panic!("Unable to build {}", tool_name) + let help = "note: not all tools are available on all nightlies\nhelp: see https://forge.rust-lang.org/infra/toolstate.html for more information"; + panic!( + "Unable to build submodule tool {} (use `missing-tools = true` to ignore this failure)\n{}", + tool_name, help + ) } } @@ -557,7 +561,7 @@ impl Step for Std { return None; } - builder.ensure(compile::Std { compiler, target }); + builder.ensure(compile::Std::new(compiler, target)); let mut tarball = Tarball::new(builder, "rust-std", &target.triple); tarball.include_target_in_component_name(true); @@ -603,7 +607,7 @@ impl Step for RustcDev { return None; } - builder.ensure(compile::Rustc { compiler, target }); + builder.ensure(compile::Rustc::new(compiler, target)); let tarball = Tarball::new(builder, "rustc-dev", &target.triple); @@ -666,7 +670,7 @@ impl Step for Analysis { return None; } - builder.ensure(compile::Std { compiler, target }); + builder.ensure(compile::Std::new(compiler, target)); let src = builder .stage_out(compiler, Mode::Std) .join(target.triple) @@ -894,8 +898,19 @@ impl Step for PlainSourceTarball { .arg(builder.src.join("./src/tools/rust-analyzer/Cargo.toml")) .arg("--sync") .arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml")) + .arg("--sync") + .arg(builder.src.join("./src/bootstrap/Cargo.toml")) .current_dir(&plain_dst_src); - builder.run(&mut cmd); + + let config = if !builder.config.dry_run { + t!(String::from_utf8(t!(cmd.output()).stdout)) + } else { + String::new() + }; + + let cargo_config_dir = plain_dst_src.join(".cargo"); + builder.create_dir(&cargo_config_dir); + builder.create(&cargo_config_dir.join("config.toml"), &config); } tarball.bare() @@ -1033,12 +1048,6 @@ impl Step for RustAnalyzer { } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - // This prevents rust-analyzer from being built for "dist" or "install" - // on the stable/beta channels. It is a nightly-only tool and should - // not be included. - if !builder.build.unstable_features() { - return None; - } let compiler = self.compiler; let target = self.target; @@ -2020,6 +2029,8 @@ impl Step for RustDev { let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); tarball.set_overlay(OverlayKind::LLVM); + builder.ensure(crate::native::Llvm { target }); + let src_bindir = builder.llvm_out(target).join("bin"); // If updating this list, you likely want to change // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index be6655ddb61d0..2852442d0be6f 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -74,6 +74,7 @@ macro_rules! book { // and checking against it?). book!( CargoBook, "src/tools/cargo/src/doc", "cargo", submodule = "src/tools/cargo"; + ClippyBook, "src/tools/clippy/book", "clippy"; EditionGuide, "src/doc/edition-guide", "edition-guide", submodule; EmbeddedBook, "src/doc/embedded-book", "embedded-book", submodule; Nomicon, "src/doc/nomicon", "nomicon", submodule; @@ -534,7 +535,9 @@ impl Step for Rustc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs) + run.crate_or_deps("rustc-main") + .path("compiler") + .default_condition(builder.config.compiler_docs) } fn make_run(run: RunConfig<'_>) { @@ -567,7 +570,7 @@ impl Step for Rustc { // Build the standard library, so that proc-macros can use it. // (Normally, only the metadata would be necessary, but proc-macros are special since they run at compile-time.) let compiler = builder.compiler(stage, builder.config.build); - builder.ensure(compile::Std { compiler, target: builder.config.build }); + builder.ensure(compile::Std::new(compiler, builder.config.build)); builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); @@ -643,7 +646,7 @@ impl Step for Rustc { } macro_rules! tool_doc { - ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?] $(,)?) => { + ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?], in_tree = $in_tree:expr $(,)?) => { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $tool { target: TargetSelection, @@ -656,7 +659,7 @@ macro_rules! tool_doc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.krate($should_run).default_condition(builder.config.compiler_docs) + run.crate_or_deps($should_run).default_condition(builder.config.compiler_docs) } fn make_run(run: RunConfig<'_>) { @@ -683,7 +686,7 @@ macro_rules! tool_doc { // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed // with strange errors, but only on a full bors test ... let compiler = builder.compiler(stage, builder.config.build); - builder.ensure(compile::Rustc { compiler, target }); + builder.ensure(compile::Rustc::new(compiler, target)); builder.info( &format!( @@ -699,6 +702,12 @@ macro_rules! tool_doc { t!(fs::create_dir_all(&out_dir)); t!(symlink_dir_force(&builder.config, &out, &out_dir)); + let source_type = if $in_tree == true { + SourceType::InTree + } else { + SourceType::Submodule + }; + // Build cargo command. let mut cargo = prepare_tool_cargo( builder, @@ -707,7 +716,7 @@ macro_rules! tool_doc { target, "doc", $path, - SourceType::InTree, + source_type, &[], ); @@ -723,20 +732,38 @@ macro_rules! tool_doc { cargo.rustdocflag("--show-type-layout"); cargo.rustdocflag("--generate-link-to-definition"); cargo.rustdocflag("-Zunstable-options"); - builder.run(&mut cargo.into()); + if $in_tree == true { + builder.run(&mut cargo.into()); + } else { + // Allow out-of-tree docs to fail (since the tool might be in a broken state). + if !builder.try_run(&mut cargo.into()) { + builder.info(&format!( + "WARNING: tool {} failed to document; ignoring failure because it is an out-of-tree tool", + stringify!($tool).to_lowercase(), + )); + } + } } } } } -tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", ["rustdoc", "rustdoc-json-types"]); +tool_doc!( + Rustdoc, + "rustdoc-tool", + "src/tools/rustdoc", + ["rustdoc", "rustdoc-json-types"], + in_tree = true +); tool_doc!( Rustfmt, "rustfmt-nightly", "src/tools/rustfmt", ["rustfmt-nightly", "rustfmt-config_proc_macro"], + in_tree = true ); -tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]); +tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"], in_tree = true); +tool_doc!(Miri, "miri", "src/tools/miri", ["miri"], in_tree = false); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { @@ -866,7 +893,7 @@ impl Step for RustcBook { let rustc = builder.rustc(self.compiler); // The tool runs `rustc` for extracting output examples, so it needs a // functional sysroot. - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + builder.ensure(compile::Std::new(self.compiler, self.target)); let mut cmd = builder.tool_cmd(Tool::LintDocs); cmd.arg("--src"); cmd.arg(builder.src.join("compiler")); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 9d4bb978bdc4d..1822c2936b71f 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -4,7 +4,6 @@ //! has various flags to configure how it's run. use std::path::PathBuf; -use std::process; use getopts::Options; @@ -51,6 +50,7 @@ pub struct Flags { pub host: Option<Vec<TargetSelection>>, pub target: Option<Vec<TargetSelection>>, pub config: Option<PathBuf>, + pub build_dir: Option<PathBuf>, pub jobs: Option<u32>, pub cmd: Subcommand, pub incremental: bool, @@ -91,6 +91,10 @@ pub enum Subcommand { Clippy { fix: bool, paths: Vec<PathBuf>, + clippy_lint_allow: Vec<String>, + clippy_lint_deny: Vec<String>, + clippy_lint_warn: Vec<String>, + clippy_lint_forbid: Vec<String>, }, Fix { paths: Vec<PathBuf>, @@ -174,6 +178,12 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); + opts.optopt( + "", + "build-dir", + "Build directory, overrides `build.build-dir` in `config.toml`", + "DIR", + ); opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); @@ -240,6 +250,10 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "PROFILE"); opts.optflag("", "llvm-profile-generate", "generate PGO profile with llvm built for rustc"); opts.optopt("", "llvm-profile-use", "use PGO profile for llvm build", "PROFILE"); + opts.optmulti("A", "", "allow certain clippy lints", "OPT"); + opts.optmulti("D", "", "deny certain clippy lints", "OPT"); + opts.optmulti("W", "", "warn about certain clippy lints", "OPT"); + opts.optmulti("F", "", "forbid certain clippy lints", "OPT"); // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on @@ -254,7 +268,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", // subcommand. println!("{}\n", subcommand_help); let exit_code = if args.is_empty() { 0 } else { 1 }; - process::exit(exit_code); + crate::detail_exit(exit_code); } }; @@ -340,7 +354,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", } else if verbose { panic!("No paths available for subcommand `{}`", subcommand.as_str()); } - process::exit(exit_code); + crate::detail_exit(exit_code); }; // Done specifying what options are possible, so do the getopts parsing @@ -372,7 +386,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ You may need to move some options to after the subcommand.\n" ); - process::exit(1); + crate::detail_exit(1); } // Extra help text for some commands match subcommand { @@ -538,7 +552,14 @@ Arguments: } Subcommand::Check { paths } } - Kind::Clippy => Subcommand::Clippy { paths, fix: matches.opt_present("fix") }, + Kind::Clippy => Subcommand::Clippy { + paths, + fix: matches.opt_present("fix"), + clippy_lint_allow: matches.opt_strs("A"), + clippy_lint_warn: matches.opt_strs("W"), + clippy_lint_deny: matches.opt_strs("D"), + clippy_lint_forbid: matches.opt_strs("F"), + }, Kind::Fix => Subcommand::Fix { paths }, Kind::Test => Subcommand::Test { paths, @@ -593,7 +614,7 @@ Arguments: eprintln!("error: {}", err); eprintln!("help: the available profiles are:"); eprint!("{}", Profile::all_for_help("- ")); - std::process::exit(1); + crate::detail_exit(1); }) } else { t!(crate::setup::interactive_path()) @@ -607,7 +628,7 @@ Arguments: || matches.opt_str("keep-stage-std").is_some() { eprintln!("--keep-stage not yet supported for x.py check"); - process::exit(1); + crate::detail_exit(1); } } @@ -649,6 +670,7 @@ Arguments: None }, config: matches.opt_str("config").map(PathBuf::from), + build_dir: matches.opt_str("build-dir").map(PathBuf::from), jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")), cmd, incremental: matches.opt_present("incremental"), @@ -797,7 +819,7 @@ fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> { Some("warn") => Some(false), Some(value) => { eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,); - process::exit(1); + crate::detail_exit(1); } None => None, } diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 60a53c28686b0..37322670e6564 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -32,7 +32,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F code, run `./x.py fmt` instead.", cmd_debug, ); - std::process::exit(1); + crate::detail_exit(1); } } } @@ -72,7 +72,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { Err(_) => false, }; if git_available { - let in_working_tree = match Command::new("git") + let in_working_tree = match build + .config + .git() .arg("rev-parse") .arg("--is-inside-work-tree") .stdout(Stdio::null()) @@ -84,10 +86,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { }; if in_working_tree { let untracked_paths_output = output( - Command::new("git") - .arg("status") - .arg("--porcelain") - .arg("--untracked-files=normal"), + build.config.git().arg("status").arg("--porcelain").arg("--untracked-files=normal"), ); let untracked_paths = untracked_paths_output .lines() @@ -114,7 +113,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| { eprintln!("./x.py fmt is not supported on this channel"); - std::process::exit(1); + crate::detail_exit(1); }); assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); let src = build.src.clone(); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4ac857b470e80..cd421c249d8da 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -107,23 +107,18 @@ use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; use std::fs::{self, File}; +use std::io; use std::path::{Path, PathBuf}; -use std::process::{self, Command}; +use std::process::Command; use std::str; -#[cfg(unix)] -use std::os::unix::fs::symlink as symlink_file; -#[cfg(windows)] -use std::os::windows::fs::symlink_file; - use filetime::FileTime; use once_cell::sync::OnceCell; use crate::builder::Kind; use crate::config::{LlvmLibunwind, TargetSelection}; use crate::util::{ - check_run, exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed, - CiEnv, + check_run, exe, libdir, mtime, output, run, run_suppressed, try_run, try_run_suppressed, CiEnv, }; mod builder; @@ -537,6 +532,20 @@ impl Build { build.local_rebuild = true; } + // Make sure we update these before gathering metadata so we don't get an error about missing + // Cargo.toml files. + let rust_submodules = [ + "src/tools/rust-installer", + "src/tools/cargo", + "src/tools/rls", + "src/tools/miri", + "library/backtrace", + "library/stdarch", + ]; + for s in rust_submodules { + build.update_submodule(Path::new(s)); + } + build.verbose("learning about cargo"); metadata::build(&mut build); @@ -634,7 +643,8 @@ impl Build { return; } let output = output( - Command::new("git") + self.config + .git() .args(&["config", "--file"]) .arg(&self.config.src.join(".gitmodules")) .args(&["--get-regexp", "path"]), @@ -702,7 +712,7 @@ impl Build { for failure in failures.iter() { eprintln!(" - {}\n", failure); } - process::exit(1); + detail_exit(1); } #[cfg(feature = "build-metrics")] @@ -1270,14 +1280,11 @@ impl Build { // Figure out how many merge commits happened since we branched off master. // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) - let count = output( - Command::new("git") - .arg("rev-list") - .arg("--count") - .arg("--merges") - .arg("refs/remotes/origin/master..HEAD") - .current_dir(&self.src), - ); + let count = + output(self.config.git().arg("rev-list").arg("--count").arg("--merges").arg(format!( + "refs/remotes/origin/{}..HEAD", + self.config.stage0_metadata.config.nightly_branch + ))); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); n @@ -1446,7 +1453,7 @@ impl Build { src = t!(fs::canonicalize(src)); } else { let link = t!(fs::read_link(src)); - t!(symlink_file(link, dst)); + t!(self.symlink_file(link, dst)); return; } } @@ -1571,6 +1578,14 @@ impl Build { iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter() } + fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::Result<()> { + #[cfg(unix)] + use std::os::unix::fs::symlink as symlink_file; + #[cfg(windows)] + use std::os::windows::fs::symlink_file; + if !self.config.dry_run { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) } + } + fn remove(&self, f: &Path) { if self.config.dry_run { return; @@ -1600,7 +1615,7 @@ Alternatively, set `download-ci-llvm = true` in that `[llvm]` section to download LLVM rather than building it. " ); - std::process::exit(1); + detail_exit(1); } } @@ -1629,6 +1644,20 @@ fn chmod(path: &Path, perms: u32) { #[cfg(windows)] fn chmod(_path: &Path, _perms: u32) {} +/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) +/// If the test is running and code is an error code, it will cause a panic. +fn detail_exit(code: i32) -> ! { + // Successful exit + if code == 0 { + std::process::exit(0); + } + if cfg!(test) { + panic!("status code: {}", code); + } else { + std::panic::resume_unwind(Box::new(code)); + } +} + impl Compiler { pub fn with_stage(mut self, stage: u32) -> Compiler { self.stage = stage; diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 329bb68672ee6..01e70b3fb2dd7 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -18,6 +18,7 @@ use std::process::Command; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::config::TargetSelection; +use crate::util::get_clang_cl_resource_dir; use crate::util::{self, exe, output, program_out_of_date, t, up_to_date}; use crate::{CLang, GitRepo}; @@ -118,7 +119,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { if !config.llvm_from_ci { return; } - let mut rev_list = Command::new("git"); + let mut rev_list = config.git(); rev_list.args(&[ PathBuf::from("rev-list"), format!("--author={}", builder.config.stage0_metadata.config.git_merge_commit_email).into(), @@ -147,9 +148,22 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { let key = format!("{}{}", llvm_sha, config.llvm_assertions); if program_out_of_date(&llvm_stamp, &key) && !config.dry_run { download_ci_llvm(builder, &llvm_sha); - for binary in ["llvm-config", "FileCheck"] { - builder.fix_bin_or_dylib(&llvm_root.join("bin").join(binary)); - } + for entry in t!(fs::read_dir(llvm_root.join("bin"))) { + builder.fix_bin_or_dylib(&t!(entry).path()); + } + + // Update the timestamp of llvm-config to force rustc_llvm to be + // rebuilt. This is a hacky workaround for a deficiency in Cargo where + // the rerun-if-changed directive doesn't handle changes very well. + // https://github.com/rust-lang/cargo/issues/10791 + // Cargo only compares the timestamp of the file relative to the last + // time `rustc_llvm` build script ran. However, the timestamps of the + // files in the tarball are in the past, so it doesn't trigger a + // rebuild. + let now = filetime::FileTime::from_system_time(std::time::SystemTime::now()); + let llvm_config = llvm_root.join("bin").join(exe("llvm-config", builder.config.build)); + t!(filetime::set_file_times(&llvm_config, now, now)); + let llvm_lib = llvm_root.join("lib"); for entry in t!(fs::read_dir(&llvm_lib)) { let lib = t!(entry).path(); @@ -238,9 +252,7 @@ impl Step for Llvm { }; builder.update_submodule(&Path::new("src").join("llvm-project")); - if builder.llvm_link_shared() - && (target.contains("windows") || target.contains("apple-darwin")) - { + if builder.llvm_link_shared() && target.contains("windows") { panic!("shared linking to LLVM is not currently supported on {}", target.triple); } @@ -346,7 +358,9 @@ impl Step for Llvm { // // If we're not linking rustc to a dynamic LLVM, though, then don't link // tools to it. - if builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared() { + let llvm_link_shared = + builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared(); + if llvm_link_shared { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } @@ -416,27 +430,35 @@ impl Step for Llvm { // should use llvm-tblgen from there, also should verify that it // actually exists most of the time in normal installs of LLVM. let host_bin = builder.llvm_out(builder.config.build).join("bin"); - cfg.define("CMAKE_CROSSCOMPILING", "True"); cfg.define("LLVM_TABLEGEN", host_bin.join("llvm-tblgen").with_extension(EXE_EXTENSION)); + // LLVM_NM is required for cross compiling using MSVC cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION)); cfg.define( "LLVM_CONFIG_PATH", host_bin.join("llvm-config").with_extension(EXE_EXTENSION), ); + if builder.config.llvm_clang { + let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin"); + let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION); + if !builder.config.dry_run && !clang_tblgen.exists() { + panic!("unable to find {}", clang_tblgen.display()); + } + cfg.define("CLANG_TABLEGEN", clang_tblgen); + } } - if let Some(ref suffix) = builder.config.llvm_version_suffix { + let llvm_version_suffix = if let Some(ref suffix) = builder.config.llvm_version_suffix { // Allow version-suffix="" to not define a version suffix at all. - if !suffix.is_empty() { - cfg.define("LLVM_VERSION_SUFFIX", suffix); - } + if !suffix.is_empty() { Some(suffix.to_string()) } else { None } } else if builder.config.channel == "dev" { // Changes to a version suffix require a complete rebuild of the LLVM. // To avoid rebuilds during a time of version bump, don't include rustc // release number on the dev channel. - cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev"); + Some("-rust-dev".to_string()) } else { - let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel); + Some(format!("-rust-{}-{}", builder.version, builder.config.channel)) + }; + if let Some(ref suffix) = llvm_version_suffix { cfg.define("LLVM_VERSION_SUFFIX", suffix); } @@ -465,6 +487,25 @@ impl Step for Llvm { cfg.build(); + // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned + // libLLVM.dylib will be built. However, llvm-config will still look + // for a versioned path like libLLVM-14.dylib. Manually create a symbolic + // link to make llvm-config happy. + if llvm_link_shared && target.contains("apple-darwin") { + let mut cmd = Command::new(&build_llvm_config); + let version = output(cmd.arg("--version")); + let major = version.split('.').next().unwrap(); + let lib_name = match llvm_version_suffix { + Some(s) => format!("libLLVM-{}{}.dylib", major, s), + None => format!("libLLVM-{}.dylib", major), + }; + + let lib_llvm = out_dir.join("build").join("lib").join(lib_name); + if !lib_llvm.exists() { + t!(builder.symlink_file("libLLVM.dylib", &lib_llvm)); + } + } + t!(stamp.write()); build_llvm_config @@ -513,6 +554,8 @@ fn configure_cmake( cfg.target(&target.triple).host(&builder.config.build.triple); if target != builder.config.build { + cfg.define("CMAKE_CROSSCOMPILING", "True"); + if target.contains("netbsd") { cfg.define("CMAKE_SYSTEM_NAME", "NetBSD"); } else if target.contains("freebsd") { @@ -530,6 +573,17 @@ fn configure_cmake( // Since, the LLVM itself makes rather limited use of version checks in // CMakeFiles (and then only in tests), and so far no issues have been // reported, the system version is currently left unset. + + if target.contains("darwin") { + // Make sure that CMake does not build universal binaries on macOS. + // Explicitly specifiy the one single target architecture. + if target.starts_with("aarch64") { + // macOS uses a different name for building arm64 + cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64"); + } else { + cfg.define("CMAKE_OSX_ARCHITECTURES", target.triple.split('-').next().unwrap()); + } + } } let sanitize_cc = |cc: &Path| { @@ -723,7 +777,22 @@ impl Step for Lld { t!(fs::create_dir_all(&out_dir)); let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld")); - configure_cmake(builder, target, &mut cfg, true, LdFlags::default()); + let mut ldflags = LdFlags::default(); + + // When building LLD as part of a build with instrumentation on windows, for example + // when doing PGO on CI, cmake or clang-cl don't automatically link clang's + // profiler runtime in. In that case, we need to manually ask cmake to do it, to avoid + // linking errors, much like LLVM's cmake setup does in that situation. + if builder.config.llvm_profile_generate && target.contains("msvc") { + if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() { + // Find clang's runtime library directory and push that as a search path to the + // cmake linker flags. + let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + ldflags.push_all(&format!("/libpath:{}", clang_rt_dir.display())); + } + } + + configure_cmake(builder, target, &mut cfg, true, ldflags); // This is an awful, awful hack. Discovered when we migrated to using // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 64c5dd7aea720..cae41286f0871 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -104,7 +104,7 @@ You should install cmake, or set `download-ci-llvm = true` in the than building it. " ); - std::process::exit(1); + crate::detail_exit(1); } } diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 82f55440ce50c..a5a39a5a3cfc6 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -94,7 +94,7 @@ pub fn setup(config: &Config, profile: Profile) { "note: this will use the configuration in {}", profile.include_path(&config.src).display() ); - std::process::exit(1); + crate::detail_exit(1); } let settings = format!( @@ -136,7 +136,7 @@ pub fn setup(config: &Config, profile: Profile) { println!(); - t!(install_git_hook_maybe(&config.src)); + t!(install_git_hook_maybe(&config)); println!(); @@ -287,7 +287,7 @@ pub fn interactive_path() -> io::Result<Profile> { io::stdin().read_line(&mut input)?; if input.is_empty() { eprintln!("EOF on stdin, when expecting answer to question. Giving up."); - std::process::exit(1); + crate::detail_exit(1); } break match parse_with_abbrev(&input) { Ok(profile) => profile, @@ -302,7 +302,7 @@ pub fn interactive_path() -> io::Result<Profile> { } // install a git hook to automatically run tidy --bless, if they want -fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> { +fn install_git_hook_maybe(config: &Config) -> io::Result<()> { let mut input = String::new(); println!( "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality. @@ -328,13 +328,12 @@ undesirable, simply delete the `pre-push` file from .git/hooks." }; if should_install { - let src = src_path.join("src").join("etc").join("pre-push.sh"); - let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map( - |output| { + let src = config.src.join("src").join("etc").join("pre-push.sh"); + let git = + t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| { assert!(output.status.success(), "failed to run `git`"); PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - } - )); + })); let dst = git.join("hooks").join("pre-push"); match fs::hard_link(src, &dst) { Err(e) => eprintln!( diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 9958306b5765c..4c6b5ba0afc08 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -225,7 +225,7 @@ impl Step for Cargotest { /// test` to ensure that we don't regress the test suites there. fn run(self, builder: &Builder<'_>) { let compiler = builder.compiler(self.stage, self.host); - builder.ensure(compile::Rustc { compiler, target: compiler.host }); + builder.ensure(compile::Rustc::new(compiler, compiler.host)); let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host }); // Note that this is a short, cryptic, and not scoped directory name. This @@ -603,7 +603,7 @@ impl Step for CompiletestTest { // We need `ToolStd` for the locally-built sysroot because // compiletest uses unstable features of the `test` crate. - builder.ensure(compile::Std { compiler, target: host }); + builder.ensure(compile::Std::new(compiler, host)); let cargo = tool::prepare_tool_cargo( builder, compiler, @@ -673,7 +673,7 @@ impl Step for Clippy { } if !builder.config.cmd.bless() { - std::process::exit(1); + crate::detail_exit(1); } let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run"); @@ -896,7 +896,7 @@ impl Step for RustdocGUI { let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available"); let npm = builder.config.npm.as_ref().expect("npm isn't available"); - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + builder.ensure(compile::Std::new(self.compiler, self.target)); // The goal here is to check if the necessary packages are installed, and if not, we // panic. @@ -1021,7 +1021,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` PATH = inferred_rustfmt_dir.display(), CHAN = builder.config.channel, ); - std::process::exit(1); + crate::detail_exit(1); } crate::format::format(&builder, !builder.config.cmd.bless(), &[]); } @@ -1251,7 +1251,7 @@ help: to test the compiler, use `--stage 1` instead help: to test the standard library, use `--stage 0 library/std` instead note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." ); - std::process::exit(1); + crate::detail_exit(1); } let compiler = self.compiler; @@ -1273,12 +1273,12 @@ note: if you're sure you want to do this, please open an issue as to why. In the } if suite.ends_with("fulldeps") { - builder.ensure(compile::Rustc { compiler, target }); + builder.ensure(compile::Rustc::new(compiler, target)); } - builder.ensure(compile::Std { compiler, target }); + builder.ensure(compile::Std::new(compiler, target)); // ensure that `libproc_macro` is available on the host. - builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Std::new(compiler, compiler.host)); // Also provide `rust_test_helpers` for the host. builder.ensure(native::TestHelpers { target: compiler.host }); @@ -1363,13 +1363,10 @@ note: if you're sure you want to do this, please open an issue as to why. In the if let Some(ref npm) = builder.config.npm { cmd.arg("--npm").arg(npm); } - - let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; - if !is_rustdoc { - if builder.config.rust_optimize_tests { - flags.push("-O".to_string()); - } + if builder.config.rust_optimize_tests { + cmd.arg("--optimize-tests"); } + let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); flags.push(builder.config.cmd.rustc_args().join(" ")); @@ -1646,7 +1643,7 @@ impl BookTest { fn run_ext_doc(self, builder: &Builder<'_>) { let compiler = self.compiler; - builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Std::new(compiler, compiler.host)); // mdbook just executes a binary named "rustdoc", so we need to update // PATH so that it points to our rustdoc. @@ -1674,7 +1671,7 @@ impl BookTest { fn run_local_doc(self, builder: &Builder<'_>) { let compiler = self.compiler; - builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Std::new(compiler, compiler.host)); // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` @@ -1793,7 +1790,7 @@ impl Step for ErrorIndex { builder.run_quiet(&mut tool); // The tests themselves need to link to std, so make sure it is // available. - builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Std::new(compiler, compiler.host)); markdown_test(builder, compiler, &output); } } @@ -1870,7 +1867,7 @@ impl Step for CrateLibrustc { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.krate("rustc-main") + run.crate_or_deps("rustc-main") } fn make_run(run: RunConfig<'_>) { @@ -1912,7 +1909,7 @@ impl Step for Crate { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.krate("test") + run.crate_or_deps("test") } fn make_run(run: RunConfig<'_>) { @@ -1943,7 +1940,7 @@ impl Step for Crate { let mode = self.mode; let test_kind = self.test_kind; - builder.ensure(compile::Std { compiler, target }); + builder.ensure(compile::Std::new(compiler, target)); builder.ensure(RemoteCopyLibs { compiler, target }); // If we're not doing a full bootstrap but we're testing a stage2 @@ -2065,7 +2062,7 @@ impl Step for CrateRustdoc { // isn't really necessary. builder.compiler_for(builder.top_stage, target, target) }; - builder.ensure(compile::Rustc { compiler, target }); + builder.ensure(compile::Rustc::new(compiler, target)); let mut cargo = tool::prepare_tool_cargo( builder, @@ -2180,7 +2177,7 @@ impl Step for CrateRustdocJsonTypes { // `compiler`, then it would cause rustdoc to be built *again*, which // isn't really necessary. let compiler = builder.compiler_for(builder.top_stage, target, target); - builder.ensure(compile::Rustc { compiler, target }); + builder.ensure(compile::Rustc::new(compiler, target)); let mut cargo = tool::prepare_tool_cargo( builder, @@ -2248,7 +2245,7 @@ impl Step for RemoteCopyLibs { return; } - builder.ensure(compile::Std { compiler, target }); + builder.ensure(compile::Std::new(compiler, target)); builder.info(&format!("REMOTE copy libs to emulator ({})", target)); @@ -2418,7 +2415,7 @@ impl Step for TierCheck { /// Tests the Platform Support page in the rustc book. fn run(self, builder: &Builder<'_>) { - builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host }); + builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); let mut cargo = tool::prepare_tool_cargo( builder, self.compiler, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 905fa431d29d1..f659ccbe2507f 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::env; use std::fs; use std::path::{Path, PathBuf}; -use std::process::{exit, Command}; +use std::process::Command; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::channel::GitInfo; @@ -51,10 +51,10 @@ impl Step for ToolBuild { match self.mode { Mode::ToolRustc => { - builder.ensure(compile::Std { compiler, target: compiler.host }); - builder.ensure(compile::Rustc { compiler, target }); + builder.ensure(compile::Std::new(compiler, compiler.host)); + builder.ensure(compile::Rustc::new(compiler, target)); } - Mode::ToolStd => builder.ensure(compile::Std { compiler, target }), + Mode::ToolStd => builder.ensure(compile::Std::new(compiler, target)), Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs _ => panic!("unexpected Mode for tool build"), } @@ -204,7 +204,7 @@ impl Step for ToolBuild { if !is_expected { if !is_optional_tool { - exit(1); + crate::detail_exit(1); } else { None } @@ -367,7 +367,7 @@ bootstrap_tool!( Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true; BuildManifest, "src/tools/build-manifest", "build-manifest"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; - RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true; + RustInstaller, "src/tools/rust-installer", "rust-installer", is_external_tool = true; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; LintDocs, "src/tools/lint-docs", "lint-docs"; @@ -512,8 +512,8 @@ impl Step for Rustdoc { // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build // it. - builder.ensure(compile::Std { compiler: build_compiler, target: target_compiler.host }); - builder.ensure(compile::Rustc { compiler: build_compiler, target: target_compiler.host }); + builder.ensure(compile::Std::new(build_compiler, target_compiler.host)); + builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host)); // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0 // compiler, since you do just as much work. if !builder.config.dry_run && builder.download_rustc() && build_compiler.stage == 0 { @@ -780,7 +780,7 @@ tool_extended!((self, builder), // and this is close enough for now. RustDemangler, rust_demangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {}; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {}; - RustAnalyzer, rust_analyzer, "src/tools/rust-analyzer/crates/rust-analyzer", "rust-analyzer", stable=false, submodule="rust-analyzer", {}; + RustAnalyzer, rust_analyzer, "src/tools/rust-analyzer/crates/rust-analyzer", "rust-analyzer", stable=true, submodule="rust-analyzer", {}; ); impl<'a> Builder<'a> { diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 3ee6a42d987a0..2cfeae7dc7858 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -93,7 +93,7 @@ fn print_error(tool: &str, submodule: &str) { eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool); eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule); eprintln!("proper steps."); - std::process::exit(3); + crate::detail_exit(3); } fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { @@ -108,7 +108,7 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { Ok(o) => o, Err(e) => { eprintln!("Failed to get changed files: {:?}", e); - std::process::exit(1); + crate::detail_exit(1); } }; @@ -179,7 +179,7 @@ impl Step for ToolStateCheck { } if did_error { - std::process::exit(1); + crate::detail_exit(1); } check_changed_files(&toolstates); @@ -225,7 +225,7 @@ impl Step for ToolStateCheck { } if did_error { - std::process::exit(1); + crate::detail_exit(1); } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 4b2b058a780f6..1895e2901489e 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -22,6 +22,7 @@ use crate::config::{Config, TargetSelection}; /// /// This is currently used judiciously throughout the build system rather than /// using a `Result` with `try!`, but this may change one day... +#[macro_export] macro_rules! t { ($e:expr) => { match $e { @@ -37,7 +38,7 @@ macro_rules! t { } }; } -pub(crate) use t; +pub use t; /// Given an executable called `name`, return the filename for the /// executable for a particular target. @@ -297,7 +298,8 @@ pub fn use_host_linker(target: TargetSelection) -> bool { || target.contains("nvptx") || target.contains("fortanix") || target.contains("fuchsia") - || target.contains("bpf")) + || target.contains("bpf") + || target.contains("switch")) } pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( @@ -335,7 +337,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { if !try_run(cmd, print_cmd_on_fail) { - std::process::exit(1); + crate::detail_exit(1); } } @@ -374,7 +376,7 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { pub fn run_suppressed(cmd: &mut Command) { if !try_run_suppressed(cmd) { - std::process::exit(1); + crate::detail_exit(1); } } @@ -464,7 +466,7 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { fn fail(s: &str) -> ! { eprintln!("\n\n{}\n\n", s); - std::process::exit(1); + crate::detail_exit(1); } /// Copied from `std::path::absolute` until it stabilizes. @@ -575,3 +577,27 @@ fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBu } } } + +/// Adapted from https://github.com/llvm/llvm-project/blob/782e91224601e461c019e0a4573bbccc6094fbcd/llvm/cmake/modules/HandleLLVMOptions.cmake#L1058-L1079 +/// +/// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource +/// directory to the linker flags, otherwise there will be linker errors about the profiler runtime +/// missing. This function returns the path to that directory. +pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf { + // Similar to how LLVM does it, to find clang's library runtime directory: + // - we ask `clang-cl` to locate the `clang_rt.builtins` lib. + let mut builtins_locator = Command::new(clang_cl_path); + builtins_locator.args(&["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]); + + let clang_rt_builtins = output(&mut builtins_locator); + let clang_rt_builtins = Path::new(clang_rt_builtins.trim()); + assert!( + clang_rt_builtins.exists(), + "`clang-cl` must correctly locate the library runtime directory" + ); + + // - the profiler runtime will be located in the same directory as the builtins lib, like + // `$LLVM_DISTRO_ROOT/lib/clang/$LLVM_VERSION/lib/windows`. + let clang_rt_dir = clang_rt_builtins.parent().expect("The clang lib folder should exist"); + clang_rt_dir.to_path_buf() +} diff --git a/src/ci/docker/host-x86_64/dist-various-2/shared.sh b/src/ci/docker/host-x86_64/dist-various-2/shared.sh index 267d8b79cc28b..291f26bdaeb37 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/shared.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/shared.sh @@ -33,15 +33,3 @@ function retry { } done } - -# Copied from ../../init_repo.sh -function fetch_github_commit_archive { - local module=$1 - local cached="download-${module//\//-}.tar.gz" - retry sh -c "rm -f $cached && \ - curl -f -sSL -o $cached $2" - mkdir $module - touch "$module/.git" - tar -C $module --strip-components=1 -xf $cached - rm $cached -} 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 495c539d06988..1025f5bce802c 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-14.0.2 +LLVM=llvmorg-14.0.5 mkdir llvm-project cd llvm-project diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 7651947c5250b..13d440423b20b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -35,7 +35,6 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ --enable-lld \ - --enable-optimize \ --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ 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 9cf038687f117..bae256fd5b38a 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.9.6 \ No newline at end of file +0.9.7 \ No newline at end of file diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index 65e1595055942..3e5dc4af04a35 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -33,7 +33,7 @@ if [ ! -d $MUSL ]; then fi cd $MUSL -./configure --enable-optimize --enable-debug --disable-shared --prefix=/musl-$TAG "$@" +./configure --enable-debug --disable-shared --prefix=/musl-$TAG "$@" if [ "$TAG" = "i586" -o "$TAG" = "i686" ]; then hide_output make -j$(nproc) AR=ar RANLIB=ranlib else diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 57832ac2b9594..f92e46b0a97f6 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -625,7 +625,7 @@ jobs: --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler - SCRIPT: python x.py dist + SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh deleted file mode 100755 index e8c1e2b0f59ae..0000000000000 --- a/src/ci/init_repo.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o pipefail -set -o nounset - -ci_dir=$(cd $(dirname $0) && pwd) -. "$ci_dir/shared.sh" - -REPO_DIR="$1" -CACHE_DIR="$2" - -cache_src_dir="$CACHE_DIR/src" - -if [ ! -d "$REPO_DIR" -o ! -d "$REPO_DIR/.git" ]; then - echo "Error: $REPO_DIR does not exist or is not a git repo" - exit 1 -fi -cd $REPO_DIR -if [ ! -d "$CACHE_DIR" ]; then - echo "Error: $CACHE_DIR does not exist or is not an absolute path" - exit 1 -fi - -rm -rf "$CACHE_DIR" -mkdir "$CACHE_DIR" - -# On the beta channel we'll be automatically calculating the prerelease version -# via the git history, so unshallow our shallow clone from CI. -if [ "$(releaseChannel)" = "beta" ]; then - git fetch origin --unshallow beta master -fi - -# Duplicated in docker/dist-various-2/shared.sh -function fetch_github_commit_archive { - local module=$1 - local cached="download-${module//\//-}.tar.gz" - retry sh -c "rm -f $cached && \ - curl -f -sSL -o $cached $2" - mkdir $module - touch "$module/.git" - # On Windows, the default behavior is to emulate symlinks by copying - # files. However, that ends up being order-dependent while extracting, - # which can cause a failure if the symlink comes first. This env var - # causes tar to use real symlinks instead, which are allowed to dangle. - export MSYS=winsymlinks:nativestrict - tar -C $module --strip-components=1 -xf $cached - rm $cached -} - -# Archive downloads are temporarily disabled due to sudden 504 -# gateway timeout errors. -# included="src/llvm-project src/doc/book src/doc/rust-by-example" -included="" -modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" -modules=($modules) -use_git="" -urls="$(git config --file .gitmodules --get-regexp '\.url$' | cut -d' ' -f2)" -urls=($urls) -# shellcheck disable=SC2068 -for i in ${!modules[@]}; do - module=${modules[$i]} - if [[ " $included " = *" $module "* ]]; then - commit="$(git ls-tree HEAD $module | awk '{print $3}')" - git rm $module - url=${urls[$i]} - url=${url/\.git/} - fetch_github_commit_archive $module "$url/archive/$commit.tar.gz" & - bg_pids[${i}]=$! - continue - else - use_git="$use_git $module" - fi -done -retry sh -c "git submodule deinit -f $use_git && \ - git submodule sync && \ - git submodule update -j 16 --init --recursive --depth 1 $use_git" -# STATUS=0 -# for pid in ${bg_pids[*]} -# do -# wait $pid || STATUS=1 -# done -# exit ${STATUS} diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh index 9de970c9c2aa5..28bed1fa0353b 100755 --- a/src/ci/pgo.sh +++ b/src/ci/pgo.sh @@ -3,44 +3,82 @@ set -euxo pipefail +ci_dir=`cd $(dirname $0) && pwd` +source "$ci_dir/shared.sh" + +# The root checkout, where the source is located +CHECKOUT=/checkout + +DOWNLOADED_LLVM=/rustroot + +# The main directory where the build occurs, which can be different between linux and windows +BUILD_ROOT=$CHECKOUT/obj + +if isWindows; then + CHECKOUT=$(pwd) + DOWNLOADED_LLVM=$CHECKOUT/citools/clang-rust + BUILD_ROOT=$CHECKOUT +fi + +# The various build artifacts used in other commands: to launch rustc builds, build the perf +# collector, and run benchmarks to gather profiling data +BUILD_ARTIFACTS=$BUILD_ROOT/build/$PGO_HOST +RUSTC_STAGE_0=$BUILD_ARTIFACTS/stage0/bin/rustc +CARGO_STAGE_0=$BUILD_ARTIFACTS/stage0/bin/cargo +RUSTC_STAGE_2=$BUILD_ARTIFACTS/stage2/bin/rustc + +# Windows needs these to have the .exe extension +if isWindows; then + RUSTC_STAGE_0="${RUSTC_STAGE_0}.exe" + CARGO_STAGE_0="${CARGO_STAGE_0}.exe" + RUSTC_STAGE_2="${RUSTC_STAGE_2}.exe" +fi + +# Make sure we have a temporary PGO work folder +PGO_TMP=/tmp/tmp-pgo +mkdir -p $PGO_TMP +rm -rf $PGO_TMP/* + +RUSTC_PERF=$PGO_TMP/rustc-perf + # Compile several crates to gather execution PGO profiles. # Arg0 => profiles (Debug, Opt) # Arg1 => scenarios (Full, IncrFull, All) # Arg2 => crates (syn, cargo, ...) gather_profiles () { - cd /checkout/obj + cd $BUILD_ROOT # Compile libcore, both in opt-level=0 and opt-level=3 - RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \ - --edition=2021 --crate-type=lib ../library/core/src/lib.rs - RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \ - --edition=2021 --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs + RUSTC_BOOTSTRAP=1 $RUSTC_STAGE_2 \ + --edition=2021 --crate-type=lib $CHECKOUT/library/core/src/lib.rs \ + --out-dir $PGO_TMP + RUSTC_BOOTSTRAP=1 $RUSTC_STAGE_2 \ + --edition=2021 --crate-type=lib -Copt-level=3 $CHECKOUT/library/core/src/lib.rs \ + --out-dir $PGO_TMP - cd rustc-perf + cd $RUSTC_PERF # Run rustc-perf benchmarks # Benchmark using profile_local with eprintln, which essentially just means # don't actually benchmark -- just make sure we run rustc a bunch of times. RUST_LOG=collector=debug \ - RUSTC=/checkout/obj/build/$PGO_HOST/stage0/bin/rustc \ + RUSTC=$RUSTC_STAGE_0 \ RUSTC_BOOTSTRAP=1 \ - /checkout/obj/build/$PGO_HOST/stage0/bin/cargo run -p collector --bin collector -- \ - profile_local \ - eprintln \ - /checkout/obj/build/$PGO_HOST/stage2/bin/rustc \ - --id Test \ - --profiles $1 \ - --cargo /checkout/obj/build/$PGO_HOST/stage0/bin/cargo \ - --scenarios $2 \ - --include $3 - - cd /checkout/obj + $CARGO_STAGE_0 run -p collector --bin collector -- \ + profile_local \ + eprintln \ + $RUSTC_STAGE_2 \ + --id Test \ + --profiles $1 \ + --cargo $CARGO_STAGE_0 \ + --scenarios $2 \ + --include $3 + + cd $BUILD_ROOT } -rm -rf /tmp/rustc-pgo - # This path has to be absolute -LLVM_PROFILE_DIRECTORY_ROOT=/tmp/llvm-pgo +LLVM_PROFILE_DIRECTORY_ROOT=$PGO_TMP/llvm-pgo # We collect LLVM profiling information and rustc profiling information in # separate phases. This increases build time -- though not by a huge amount -- @@ -49,34 +87,47 @@ LLVM_PROFILE_DIRECTORY_ROOT=/tmp/llvm-pgo # LLVM IR PGO does not respect LLVM_PROFILE_FILE, so we have to set the profiling file # path through our custom environment variable. We include the PID in the directory path # to avoid updates to profile files being lost because of race conditions. -LLVM_PROFILE_DIR=${LLVM_PROFILE_DIRECTORY_ROOT}/prof-%p python3 ../x.py build \ +LLVM_PROFILE_DIR=${LLVM_PROFILE_DIRECTORY_ROOT}/prof-%p python3 $CHECKOUT/x.py build \ --target=$PGO_HOST \ --host=$PGO_HOST \ --stage 2 library/std \ --llvm-profile-generate -# Compile rustc perf -cp -r /tmp/rustc-perf ./ -chown -R $(whoami): ./rustc-perf -cd rustc-perf - -# Build the collector ahead of time, which is needed to make sure the rustc-fake -# binary used by the collector is present. -RUSTC=/checkout/obj/build/$PGO_HOST/stage0/bin/rustc \ +# Compile rustc-perf: +# - get the expected commit source code: on linux, the Dockerfile downloads a source archive before +# running this script. On Windows, we do that here. +if isLinux; then + cp -r /tmp/rustc-perf $RUSTC_PERF + chown -R $(whoami): $RUSTC_PERF +else + # rustc-perf version from 2022-05-18 + PERF_COMMIT=f66cc8f3e04392b0e2fd811f21fd1ece6ebaded3 + retry curl -LS -o $PGO_TMP/perf.zip \ + https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \ + cd $PGO_TMP && unzip -q perf.zip && \ + mv rustc-perf-$PERF_COMMIT $RUSTC_PERF && \ + rm perf.zip +fi + +# - build rustc-perf's collector ahead of time, which is needed to make sure the rustc-fake binary +# used by the collector is present. +cd $RUSTC_PERF + +RUSTC=$RUSTC_STAGE_0 \ RUSTC_BOOTSTRAP=1 \ -/checkout/obj/build/$PGO_HOST/stage0/bin/cargo build -p collector +$CARGO_STAGE_0 build -p collector # Here we're profiling LLVM, so we only care about `Debug` and `Opt`, because we want to stress # codegen. We also profile some of the most prolific crates. gather_profiles "Debug,Opt" "Full" \ -"syn-1.0.89,cargo-0.60.0,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18" + "syn-1.0.89,cargo-0.60.0,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18" -LLVM_PROFILE_MERGED_FILE=/tmp/llvm-pgo.profdata +LLVM_PROFILE_MERGED_FILE=$PGO_TMP/llvm-pgo.profdata # Merge the profile data we gathered for LLVM # Note that this uses the profdata from the clang we used to build LLVM, # which likely has a different version than our in-tree clang. -/rustroot/bin/llvm-profdata merge -o ${LLVM_PROFILE_MERGED_FILE} ${LLVM_PROFILE_DIRECTORY_ROOT} +$DOWNLOADED_LLVM/bin/llvm-profdata merge -o ${LLVM_PROFILE_MERGED_FILE} ${LLVM_PROFILE_DIRECTORY_ROOT} echo "LLVM PGO statistics" du -sh ${LLVM_PROFILE_MERGED_FILE} @@ -84,34 +135,45 @@ du -sh ${LLVM_PROFILE_DIRECTORY_ROOT} echo "Profile file count" find ${LLVM_PROFILE_DIRECTORY_ROOT} -type f | wc -l +# We don't need the individual .profraw files now that they have been merged into a final .profdata +rm -r $LLVM_PROFILE_DIRECTORY_ROOT + # Rustbuild currently doesn't support rebuilding LLVM when PGO options # change (or any other llvm-related options); so just clear out the relevant # directories ourselves. -rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld +rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld # Okay, LLVM profiling is done, switch to rustc PGO. # The path has to be absolute -RUSTC_PROFILE_DIRECTORY_ROOT=/tmp/rustc-pgo +RUSTC_PROFILE_DIRECTORY_ROOT=$PGO_TMP/rustc-pgo -python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \ +python3 $CHECKOUT/x.py build --target=$PGO_HOST --host=$PGO_HOST \ --stage 2 library/std \ --rust-profile-generate=${RUSTC_PROFILE_DIRECTORY_ROOT} # Here we're profiling the `rustc` frontend, so we also include `Check`. # The benchmark set includes various stress tests that put the frontend under pressure. -# The profile data is written into a single filepath that is being repeatedly merged when each -# rustc invocation ends. Empirically, this can result in some profiling data being lost. -# That's why we override the profile path to include the PID. This will produce many more profiling -# files, but the resulting profile will produce a slightly faster rustc binary. -LLVM_PROFILE_FILE=${RUSTC_PROFILE_DIRECTORY_ROOT}/default_%m_%p.profraw gather_profiles \ - "Check,Debug,Opt" "All" \ - "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0" - -RUSTC_PROFILE_MERGED_FILE=/tmp/rustc-pgo.profdata +if isLinux; then + # The profile data is written into a single filepath that is being repeatedly merged when each + # rustc invocation ends. Empirically, this can result in some profiling data being lost. That's + # why we override the profile path to include the PID. This will produce many more profiling + # files, but the resulting profile will produce a slightly faster rustc binary. + LLVM_PROFILE_FILE=${RUSTC_PROFILE_DIRECTORY_ROOT}/default_%m_%p.profraw gather_profiles \ + "Check,Debug,Opt" "All" \ + "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0" +else + # On windows, we don't do that yet (because it generates a lot of data, hitting disk space + # limits on the builder), and use the default profraw merging behavior. + gather_profiles \ + "Check,Debug,Opt" "All" \ + "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0" +fi + +RUSTC_PROFILE_MERGED_FILE=$PGO_TMP/rustc-pgo.profdata # Merge the profile data we gathered -./build/$PGO_HOST/llvm/bin/llvm-profdata \ +$BUILD_ARTIFACTS/llvm/bin/llvm-profdata \ merge -o ${RUSTC_PROFILE_MERGED_FILE} ${RUSTC_PROFILE_DIRECTORY_ROOT} echo "Rustc PGO statistics" @@ -120,10 +182,13 @@ du -sh ${RUSTC_PROFILE_DIRECTORY_ROOT} echo "Profile file count" find ${RUSTC_PROFILE_DIRECTORY_ROOT} -type f | wc -l +# We don't need the individual .profraw files now that they have been merged into a final .profdata +rm -r $RUSTC_PROFILE_DIRECTORY_ROOT + # Rustbuild currently doesn't support rebuilding LLVM when PGO options # change (or any other llvm-related options); so just clear out the relevant # directories ourselves. -rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld +rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld # This produces the actual final set of artifacts, using both the LLVM and rustc # collected profiling data. diff --git a/src/ci/run.sh b/src/ci/run.sh index b0314047c070b..16d8bdb815367 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -132,7 +132,7 @@ trap datecheck EXIT SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then - $SRC/configure --enable-parallel-compiler + $SRC/configure --set rust.parallel-compiler CARGO_INCREMENTAL=0 $PYTHON ../x.py check rm -f config.toml rm -rf build diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh index 0b44ea3c90bc9..3eb4b8f905832 100755 --- a/src/ci/scripts/checkout-submodules.sh +++ b/src/ci/scripts/checkout-submodules.sh @@ -2,16 +2,70 @@ # Check out all our submodules, but more quickly than using git by using one of # our custom scripts -set -euo pipefail -IFS=$'\n\t' +set -o errexit +set -o pipefail +set -o nounset -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" +if [ ! -d ".git" ]; then + echo "Error: This must run in the root of the repository" + exit 1 +fi + +ci_dir=$(cd $(dirname $0) && pwd)/.. +. "$ci_dir/shared.sh" -if isWindows; then - path="/c/cache/rustsrc" -else - path="${HOME}/rustsrc" +# On the beta channel we'll be automatically calculating the prerelease version +# via the git history, so unshallow our shallow clone from CI. +if [ "$(releaseChannel)" = "beta" ]; then + git fetch origin --unshallow beta master fi -mkdir -p "${path}" -"$(cd "$(dirname "$0")" && pwd)/../init_repo.sh" . "${path}" +function fetch_github_commit_archive { + local module=$1 + local cached="download-${module//\//-}.tar.gz" + retry sh -c "rm -f $cached && \ + curl -f -sSL -o $cached $2" + mkdir $module + touch "$module/.git" + # On Windows, the default behavior is to emulate symlinks by copying + # files. However, that ends up being order-dependent while extracting, + # which can cause a failure if the symlink comes first. This env var + # causes tar to use real symlinks instead, which are allowed to dangle. + export MSYS=winsymlinks:nativestrict + tar -C $module --strip-components=1 -xf $cached + rm $cached +} + +# Archive downloads are temporarily disabled due to sudden 504 +# gateway timeout errors. +# included="src/llvm-project src/doc/book src/doc/rust-by-example" +included="" +modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" +modules=($modules) +use_git="" +urls="$(git config --file .gitmodules --get-regexp '\.url$' | cut -d' ' -f2)" +urls=($urls) +# shellcheck disable=SC2068 +for i in ${!modules[@]}; do + module=${modules[$i]} + if [[ " $included " = *" $module "* ]]; then + commit="$(git ls-tree HEAD $module | awk '{print $3}')" + git rm $module + url=${urls[$i]} + url=${url/\.git/} + fetch_github_commit_archive $module "$url/archive/$commit.tar.gz" & + bg_pids[${i}]=$! + continue + else + use_git="$use_git $module" + fi +done +retry sh -c "git submodule deinit -f $use_git && \ + git submodule sync && \ + git submodule update -j 16 --init --recursive --depth 1 $use_git" +# STATUS=0 +# for pid in ${bg_pids[*]} +# do +# wait $pid || STATUS=1 +# done +# exit ${STATUS} diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index 48eb88c9f9271..0bc8a0389a8d4 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -1,4 +1,5 @@ #!/bin/bash +# ignore-tidy-linelength # This script installs clang on the local machine. Note that we don't install # clang on Linux since its compiler story is just so different. Each container # has its own toolchain configured appropriately already. @@ -9,7 +10,7 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" # Update both macOS's and Windows's tarballs when bumping the version here. -LLVM_VERSION="14.0.2" +LLVM_VERSION="14.0.5" if isMacOS; then # If the job selects a specific Xcode version, use that instead of diff --git a/src/doc/book b/src/doc/book index efbafdba36184..cf2653a5ca553 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit efbafdba3618487fbc9305318fcab9775132ac15 +Subproject commit cf2653a5ca553cbbb4a17f1a7db1947820f6a775 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index e17dcef5e9634..766979590da81 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit e17dcef5e96346ee3d7fa56820ddc7e5c39636bc +Subproject commit 766979590da8100998f0d662499d4a901d8d1640 diff --git a/src/doc/index.md b/src/doc/index.md index 2c92d5e2a1803..b77790e33b70a 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -93,6 +93,10 @@ accomplishing various tasks. [The Rustdoc Book](rustdoc/index.html) describes our documentation tool, `rustdoc`. +## The Clippy Book + +[The Clippy Book](clippy/index.html) describes our static analyzer, Clippy. + ## Extended Error Listing Many of Rust's errors come with error codes, and you can request extended diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 4e7170806d47b..ff41324ef2645 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -143,7 +143,7 @@ Specify where an external rust library is located. These should match Override the system root. .TP \fB\-Z\fR \fIFLAG\fR -Set internal debugging options. +Set unstable / perma-unstable options. Use \fI\-Z help\fR to print available options. .TP \fB\-\-color\fR auto|always|never diff --git a/src/doc/nomicon b/src/doc/nomicon index 3a43983b76174..70db9e4189f64 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 3a43983b76174342b7dbd3e12ea2c49f762e52be +Subproject commit 70db9e4189f64d1d8e2451b1046111fb356b6dc2 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 1095df2a5850f..83724ca387a2a 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 1095df2a5850f2d345fad43a30633133365875ba +Subproject commit 83724ca387a2a1cd3e8d848f62820020760e358b diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 048d925f0a955..eb83839e903a0 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 048d925f0a955aac601c4160c0e7f05771bcf63b +Subproject commit eb83839e903a0a8f1406f7e941886273f189b26b diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 87dc513853968..f6348b2bddc88 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -17,6 +17,7 @@ - [Template for Target-specific Documentation](platform-support/TEMPLATE.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) - [\*-apple-watchos\*](platform-support/apple-watchos.md) + - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index eb985803266e7..7a03238f13dff 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -209,6 +209,7 @@ target | std | host | notes `aarch64-apple-tvos` | * | | ARM64 tvOS [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | ARM64 Apple WatchOS Simulator [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 +[`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore diff --git a/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md b/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md new file mode 100644 index 0000000000000..308e1fe2f92a0 --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md @@ -0,0 +1,49 @@ +# aarch64-nintendo-switch-freestanding + +**Tier: 3** + +Nintendo Switch with pure-Rust toolchain. + +## Designated Developers + +* [@leo60228](https://github.com/leo60228) +* [@jam1garner](https://github.com/jam1garner) + +## Requirements + +This target is cross-compiled. +It has no special requirements for the host. + +## Building + +The target can be built by enabling it for a `rustc` build: + +```toml +[build] +build-stage = 1 +target = ["aarch64-nintendo-switch-freestanding"] +``` + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + +## Building Rust programs + +If `rustc` has support for that target and the library artifacts are available, +then Rust programs can be built for that target: + +```text +rustc --target aarch64-nintendo-switch-freestanding your-code.rs +``` + +To generate binaries in the NRO format that can be easily run on-device, you +can use [cargo-nx](https://github.com/aarch64-switch-rs/cargo-nx): + +```text +cargo nx --triple=aarch64-nintendo-switch-freestanding +``` diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md new file mode 100644 index 0000000000000..c5e86f17df741 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md @@ -0,0 +1,9 @@ +## `dwarf-version` + +This option controls the version of DWARF that the compiler emits, on platforms +that use DWARF to encode debug information. It takes one of the following +values: + +* `2`: DWARF version 2 (the default on certain platforms, like macOS). +* `4`: DWARF version 4 (the default on certain platforms, like Linux). +* `5`: DWARF version 5. diff --git a/src/doc/unstable-book/src/compiler-flags/extern-options.md b/src/doc/unstable-book/src/compiler-flags/extern-options.md index 858eee5d2c283..dfc1de77be4e4 100644 --- a/src/doc/unstable-book/src/compiler-flags/extern-options.md +++ b/src/doc/unstable-book/src/compiler-flags/extern-options.md @@ -1,5 +1,10 @@ # `--extern` Options +* Tracking issue for `--extern` crate modifiers: [#98405](https://github.com/rust-lang/rust/issues/98405) +* Tracking issue for `noprelude`: [#98398](https://github.com/rust-lang/rust/issues/98398) +* Tracking issue for `priv`: [#98399](https://github.com/rust-lang/rust/issues/98399) +* Tracking issue for `nounused`: [#98400](https://github.com/rust-lang/rust/issues/98400) + The behavior of the `--extern` flag can be modified with `noprelude`, `priv` or `nounused` options. This is unstable feature, so you have to provide `-Zunstable-options` to enable it. diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 78470e8deb342..0bd72625f1509 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -14,7 +14,7 @@ pulldown-cmark = { version = "0.9", default-features = false } minifier = "0.2.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -smallvec = "1.6.1" +smallvec = "1.8.1" tempfile = "3" itertools = "0.10.1" regex = "1" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index fb178cbd95e7b..e6f006135e29a 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -117,7 +117,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { attrs: Default::default(), visibility: Inherited, item_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, - kind: box ImplItem(Impl { + kind: Box::new(ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, trait_: Some(trait_ref.clean(self.cx)), @@ -125,7 +125,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { items: Vec::new(), polarity, kind: ImplKind::Auto, - }), + })), cfg: None, }) } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index c591c59133111..12137667e7bf8 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { attrs: Default::default(), visibility: Inherited, item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, - kind: box ImplItem(Impl { + kind: Box::new(ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: clean_ty_generics( cx, @@ -123,8 +123,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .map(|x| x.clean(cx)) .collect::<Vec<_>>(), polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(box trait_ref.0.self_ty().clean(cx)), - }), + kind: ImplKind::Blanket(Box::new(trait_ref.0.self_ty().clean(cx))), + })), cfg: None, }); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d4c38f34b5b11..23af7d2ef1e24 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -124,8 +124,14 @@ pub(crate) fn try_inline( let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone); cx.inlined.insert(did.into()); - let mut item = - clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, box attrs, cx, cfg); + let mut item = clean::Item::from_def_id_and_attrs_and_parts( + did, + Some(name), + kind, + Box::new(attrs), + cx, + cfg, + ); if let Some(import_def_id) = import_def_id { // The visibility needs to reflect the one from the reexport and not from the "source" DefId. item.visibility = cx.tcx.visibility(import_def_id).clean(cx); @@ -506,7 +512,7 @@ pub(crate) fn build_impl( ImplKind::Normal }, }), - box merged_attrs, + Box::new(merged_attrs), cx, cfg, )); @@ -535,7 +541,7 @@ fn build_module( let prim_ty = clean::PrimitiveType::from(p); items.push(clean::Item { name: None, - attrs: box clean::Attributes::default(), + attrs: Box::new(clean::Attributes::default()), item_id: ItemId::Primitive(prim_ty, did.krate), visibility: clean::Public, kind: box clean::ImportItem(clean::Import::new_simple( diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9e5c4afc717a7..d6260b8ca06e4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -167,7 +167,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>( .collect_referenced_late_bound_regions(&poly_trait_ref) .into_iter() .filter_map(|br| match br { - ty::BrNamed(_, name) => Some(GenericParamDef { + ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime { outlives: vec![] }, }), @@ -293,10 +293,10 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> { ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx), ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)), ty::PredicateKind::ConstEvaluatable(..) => None, + ty::PredicateKind::WellFormed(..) => None, ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEquate(..) @@ -403,7 +403,7 @@ fn clean_projection<'tcx>( Type::QPath { assoc: Box::new(projection_to_path_segment(ty, cx)), should_show_cast, - self_type: box self_type, + self_type: Box::new(self_type), trait_, } } @@ -629,6 +629,7 @@ fn clean_ty_generics<'tcx>( .params .iter() .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None, ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), ty::GenericParamDefKind::Type { synthetic, .. } => { if param.name == kw::SelfUpper { @@ -1320,7 +1321,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type Type::QPath { assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)), should_show_cast, - self_type: box self_type, + self_type: Box::new(self_type), trait_, } } @@ -1340,7 +1341,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type Type::QPath { assoc: Box::new(segment.clean(cx)), should_show_cast, - self_type: box self_type, + self_type: Box::new(self_type), trait_, } } @@ -1440,7 +1441,7 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { match self.kind { TyKind::Never => Primitive(PrimitiveType::Never), - TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)), + TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))), TyKind::Rptr(ref l, ref m) => { // There are two times a `Fresh` lifetime can be created: // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. @@ -1452,9 +1453,9 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { let elided = l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh)); let lifetime = if elided { None } else { Some(l.clean(cx)) }; - BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } + BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) } } - TyKind::Slice(ty) => Slice(box ty.clean(cx)), + TyKind::Slice(ty) => Slice(Box::new(ty.clean(cx))), TyKind::Array(ty, ref length) => { let length = match length { hir::ArrayLen::Infer(_, _) => "_".to_string(), @@ -1473,7 +1474,7 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { } }; - Array(box ty.clean(cx), length) + Array(Box::new(ty.clean(cx)), length) } TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()), TyKind::OpaqueDef(item_id, _) => { @@ -1490,7 +1491,7 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; DynTrait(bounds, lifetime) } - TyKind::BareFn(barefn) => BareFunction(box barefn.clean(cx)), + TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err => Infer, TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), @@ -1501,7 +1502,7 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> { /// Returns `None` if the type could not be normalized fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> { // HACK: low-churn fix for #79459 while we wait for a trait normalization fix - if !cx.tcx.sess.opts.debugging_opts.normalize_docs { + if !cx.tcx.sess.opts.unstable_opts.normalize_docs { return None; } @@ -1540,27 +1541,27 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI ty::Uint(uint_ty) => Primitive(uint_ty.into()), ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), - ty::Slice(ty) => Slice(box ty.clean(cx)), + ty::Slice(ty) => Slice(Box::new(ty.clean(cx))), ty::Array(ty, n) => { let mut n = cx.tcx.lift(n).expect("array lift failed"); n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); - Array(box ty.clean(cx), n) + Array(Box::new(ty.clean(cx)), n) } - ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)), + ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))), ty::Ref(r, ty, mutbl) => { - BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) } + BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: Box::new(ty.clean(cx)) } } ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(this).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx); let decl = clean_fn_decl_from_did_and_sig(cx, None, sig); - BareFunction(box BareFunctionDecl { + BareFunction(Box::new(BareFunctionDecl { unsafety: sig.unsafety(), generic_params: Vec::new(), decl, abi: sig.abi(), - }) + })) } ty::Adt(def, substs) => { let did = def.did(); @@ -1704,8 +1705,8 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI ImplTrait(bounds) } - ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton) - + ty::Closure(..) => panic!("Closure"), + ty::Generator(..) => panic!("Generator"), ty::Bound(..) => panic!("Bound"), ty::Placeholder(..) => panic!("Placeholder"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), @@ -1759,7 +1760,6 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { match tcx.def_kind(parent) { DefKind::Struct | DefKind::Union => false, DefKind::Variant => true, - // FIXME: what about DefKind::Ctor? parent_kind => panic!("unexpected parent kind: {:?}", parent_kind), } } @@ -2062,7 +2062,7 @@ fn clean_extern_crate<'tcx>( // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason vec![Item { name: Some(name), - attrs: box attrs.clean(cx), + attrs: Box::new(attrs.clean(cx)), item_id: crate_def_id.into(), visibility: ty_vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, @@ -2120,8 +2120,9 @@ fn clean_use_statement<'tcx>( // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let mut denied = !(visibility.is_public() - || (cx.render_options.document_private && is_visible_from_parent_mod)) + let mut denied = cx.output_format.is_json() + || !(visibility.is_public() + || (cx.render_options.document_private && is_visible_from_parent_mod)) || pub_underscore || attrs.iter().any(|a| { a.has_name(sym::doc) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2762d5e8502b2..d29ba2dedaf71 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -477,7 +477,7 @@ impl Item { def_id, name, kind, - box ast_attrs.clean(cx), + Box::new(ast_attrs.clean(cx)), cx, ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) @@ -1671,10 +1671,6 @@ impl Type { matches!(self, Type::ImplTrait(_)) } - pub(crate) fn is_primitive(&self) -> bool { - self.primitive_type().is_some() - } - pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { if let QPath { self_type, trait_, assoc, .. } = self { Some((self_type, trait_.def_id(), *assoc.clone())) @@ -2161,8 +2157,12 @@ impl Path { self.res.def_id() } + pub(crate) fn last_opt(&self) -> Option<Symbol> { + self.segments.last().map(|s| s.name) + } + pub(crate) fn last(&self) -> Symbol { - self.segments.last().expect("segments were empty").name + self.last_opt().expect("segments were empty") } pub(crate) fn whole_name(&self) -> String { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 16574f94c00e9..22b1e2335fd84 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -340,17 +340,98 @@ pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { false } +/// Build a textual representation of an unevaluated constant expression. +/// +/// If the const expression is too complex, an underscore `_` is returned. +/// For const arguments, it's `{ _ }` to be precise. +/// This means that the output is not necessarily valid Rust code. +/// +/// Currently, only +/// +/// * literals (optionally with a leading `-`) +/// * unit `()` +/// * blocks (`{ … }`) around simple expressions and +/// * paths without arguments +/// +/// are considered simple enough. Simple blocks are included since they are +/// necessary to disambiguate unit from the unit type. +/// This list might get extended in the future. +/// +/// Without this censoring, in a lot of cases the output would get too large +/// and verbose. Consider `match` expressions, blocks and deeply nested ADTs. +/// Further, private and `doc(hidden)` fields of structs would get leaked +/// since HIR datatypes like the `body` parameter do not contain enough +/// semantic information for this function to be able to hide them – +/// at least not without significant performance overhead. +/// +/// Whenever possible, prefer to evaluate the constant first and try to +/// use a different method for pretty-printing. Ideally this function +/// should only ever be used as a fallback. pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { let hir = tcx.hir(); let value = &hir.body(body).value; - let snippet = if !value.span.from_expansion() { - tcx.sess.source_map().span_to_snippet(value.span).ok() - } else { - None - }; + #[derive(PartialEq, Eq)] + enum Classification { + Literal, + Simple, + Complex, + } - snippet.unwrap_or_else(|| rustc_hir_pretty::id_to_string(&hir, body.hir_id)) + use Classification::*; + + fn classify(expr: &hir::Expr<'_>) -> Classification { + match &expr.kind { + hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { + if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex } + } + hir::ExprKind::Lit(_) => Literal, + hir::ExprKind::Tup([]) => Simple, + hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => { + if classify(expr) == Complex { Complex } else { Simple } + } + // Paths with a self-type or arguments are too “complex” following our measure since + // they may leak private fields of structs (with feature `adt_const_params`). + // Consider: `<Self as Trait<{ Struct { private: () } }>>::CONSTANT`. + // Paths without arguments are definitely harmless though. + hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) => { + if segments.iter().all(|segment| segment.args.is_none()) { Simple } else { Complex } + } + // FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty + // contains const arguments. Is there a *concise* way to check for this? + hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple, + // FIXME: Can they contain const arguments and thus leak private struct fields? + hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple, + _ => Complex, + } + } + + let classification = classify(value); + + if classification == Literal + && !value.span.from_expansion() + && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) { + // For literals, we avoid invoking the pretty-printer and use the source snippet instead to + // preserve certain stylistic choices the user likely made for the sake legibility like + // + // * hexadecimal notation + // * underscores + // * character escapes + // + // FIXME: This passes through `-/*spacer*/0` verbatim. + snippet + } else if classification == Simple { + // Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and + // other formatting artifacts. + rustc_hir_pretty::id_to_string(&hir, body.hir_id) + } else if tcx.def_kind(hir.body_owner_def_id(body).to_def_id()) == DefKind::AnonConst { + // FIXME: Omit the curly braces if the enclosing expression is an array literal + // with a repeated element (an `ExprKind::Repeat`) as in such case it + // would not actually need any disambiguation. + "{ _ }".to_owned() + } else { + "_".to_owned() + } } /// Given a type Path, resolve it to a Type using the TyCtxt diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index e59324331ae34..8a8cc272e8195 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -6,12 +6,13 @@ use std::path::PathBuf; use std::str::FromStr; use rustc_data_structures::fx::FxHashMap; +use rustc_driver::print_flag_list; use rustc_session::config::{ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, }; use rustc_session::config::{get_cmd_lint_options, nightly_options}; use rustc_session::config::{ - CodegenOptions, DebuggingOptions, ErrorOutputType, Externs, JsonUnusedExterns, + CodegenOptions, ErrorOutputType, Externs, JsonUnusedExterns, UnstableOptions, }; use rustc_session::getopts; use rustc_session::lint::Level; @@ -72,6 +73,8 @@ pub(crate) struct Options { pub(crate) proc_macro_crate: bool, /// How to format errors and warnings. pub(crate) error_format: ErrorOutputType, + /// Width of output buffer to truncate errors appropriately. + pub(crate) diagnostic_width: Option<usize>, /// Library search paths to hand to the compiler. pub(crate) libs: Vec<SearchPath>, /// Library search paths strings to hand to the compiler. @@ -88,10 +91,10 @@ pub(crate) struct Options { pub(crate) codegen_options: CodegenOptions, /// Codegen options strings to hand to the compiler. pub(crate) codegen_options_strs: Vec<String>, - /// Debugging (`-Z`) options to pass to the compiler. - pub(crate) debugging_opts: DebuggingOptions, - /// Debugging (`-Z`) options strings to pass to the compiler. - pub(crate) debugging_opts_strs: Vec<String>, + /// Unstable (`-Z`) options to pass to the compiler. + pub(crate) unstable_opts: UnstableOptions, + /// Unstable (`-Z`) options strings to pass to the compiler. + pub(crate) unstable_opts_strs: Vec<String>, /// The target used to compile the crate against. pub(crate) target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when @@ -178,7 +181,7 @@ impl fmt::Debug for Options { .field("cfgs", &self.cfgs) .field("check-cfgs", &self.check_cfgs) .field("codegen_options", &"...") - .field("debugging_options", &"...") + .field("unstable_options", &"...") .field("target", &self.target) .field("edition", &self.edition) .field("maybe_sysroot", &self.maybe_sysroot) @@ -217,12 +220,9 @@ pub(crate) struct RenderOptions { /// /// Be aware: This option can come both from the CLI and from crate attributes! pub(crate) playground_url: Option<String>, - /// Whether to sort modules alphabetically on a module page instead of using declaration order. - /// `true` by default. - // - // FIXME(misdreavus): the flag name is `--sort-modules-by-appearance` but the meaning is - // inverted once read. - pub(crate) sort_modules_alphabetically: bool, + /// What sorting mode to use for module pages. + /// `ModuleSorting::Alphabetical` by default. + pub(crate) module_sorting: ModuleSorting, /// List of themes to extend the docs with. Original argument name is included to assist in /// displaying errors if it fails a theme check. pub(crate) themes: Vec<StylePath>, @@ -239,9 +239,6 @@ pub(crate) struct RenderOptions { pub(crate) resource_suffix: String, /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by /// default. - // - // FIXME(misdreavus): the flag name is `--disable-minification` but the meaning is inverted - // once read. pub(crate) enable_minification: bool, /// Whether to create an index page in the root of the output directory. If this is true but /// `enable_index_page` is None, generate a static listing of crates instead. @@ -280,6 +277,12 @@ pub(crate) struct RenderOptions { pub(crate) no_emit_shared: bool, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum ModuleSorting { + DeclarationOrder, + Alphabetical, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum EmitType { Unversioned, @@ -310,11 +313,15 @@ impl RenderOptions { impl Options { /// Parses the given command-line for options. If an error message or other early-return has /// been printed, returns `Err` with the exit code. - pub(crate) fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> { + pub(crate) fn from_matches( + matches: &getopts::Matches, + args: Vec<String>, + ) -> Result<Options, i32> { + let args = &args[1..]; // Check for unstable options. nightly_options::check_nightly_options(matches, &opts()); - if matches.opt_present("h") || matches.opt_present("help") { + if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") { crate::usage("rustdoc"); return Err(0); } else if matches.opt_present("version") { @@ -322,15 +329,27 @@ impl Options { return Err(0); } + let z_flags = matches.opt_strs("Z"); + if z_flags.iter().any(|x| *x == "help") { + print_flag_list("-Z", config::Z_OPTIONS); + return Err(0); + } + let c_flags = matches.opt_strs("C"); + if c_flags.iter().any(|x| *x == "help") { + print_flag_list("-C", config::CG_OPTIONS); + return Err(0); + } + let color = config::parse_color(matches); let config::JsonConfig { json_rendered, json_unused_externs, .. } = config::parse_json(matches); let error_format = config::parse_error_format(matches, color, json_rendered); + let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default(); let codegen_options = CodegenOptions::build(matches, error_format); - let debugging_opts = DebuggingOptions::build(matches, error_format); + let unstable_opts = UnstableOptions::build(matches, error_format); - let diag = new_handler(error_format, None, &debugging_opts); + let diag = new_handler(error_format, None, diagnostic_width, &unstable_opts); // check for deprecated options check_deprecated_options(matches, &diag); @@ -416,22 +435,26 @@ impl Options { return Err(0); } - if matches.free.is_empty() { + let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); + + let input = PathBuf::from(if describe_lints { + "" // dummy, this won't be used + } else if matches.free.is_empty() { diag.struct_err("missing file operand").emit(); return Err(1); - } - if matches.free.len() > 1 { + } else if matches.free.len() > 1 { diag.struct_err("too many file operands").emit(); return Err(1); - } - let input = PathBuf::from(&matches.free[0]); + } else { + &matches.free[0] + }); let libs = matches .opt_strs("L") .iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); - let externs = parse_externs(matches, &debugging_opts, error_format); + let externs = parse_externs(matches, &unstable_opts, error_format); let extern_html_root_urls = match parse_extern_html_roots(matches) { Ok(ex) => ex, Err(err) => { @@ -630,7 +653,11 @@ impl Options { let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); - let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance"); + let module_sorting = if matches.opt_present("sort-modules-by-appearance") { + ModuleSorting::DeclarationOrder + } else { + ModuleSorting::Alphabetical + }; let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default(); let enable_minification = !matches.opt_present("disable-minification"); let markdown_no_toc = matches.opt_present("markdown-no-toc"); @@ -643,7 +670,7 @@ impl Options { let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let test_builder = matches.opt_str("test-builder").map(PathBuf::from); let codegen_options_strs = matches.opt_strs("C"); - let debugging_opts_strs = matches.opt_strs("Z"); + let unstable_opts_strs = matches.opt_strs("Z"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); let runtool = matches.opt_str("runtool"); @@ -671,12 +698,11 @@ impl Options { let with_examples = matches.opt_strs("with-examples"); let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?; - let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); - Ok(Options { input, proc_macro_crate, error_format, + diagnostic_width, libs, lib_strs, externs, @@ -685,8 +711,8 @@ impl Options { check_cfgs, codegen_options, codegen_options_strs, - debugging_opts, - debugging_opts_strs, + unstable_opts, + unstable_opts_strs, target, edition, maybe_sysroot, @@ -711,7 +737,7 @@ impl Options { external_html, id_map, playground_url, - sort_modules_alphabetically, + module_sorting, themes, extension_css, extern_html_root_urls, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 51b245e36ba3b..0e9a9e0e50646 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,7 +32,7 @@ use crate::formats::cache::Cache; use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink; use crate::passes::{self, Condition::*}; -pub(crate) use rustc_session::config::{DebuggingOptions, Input, Options}; +pub(crate) use rustc_session::config::{Input, Options, UnstableOptions}; pub(crate) struct ResolverCaches { pub(crate) markdown_links: Option<FxHashMap<String, Vec<PreprocessedMarkdownLink>>>, @@ -81,6 +81,8 @@ pub(crate) struct DocContext<'tcx> { pub(crate) inlined: FxHashSet<ItemId>, /// Used by `calculate_doc_coverage`. pub(crate) output_format: OutputFormat, + /// Used by `strip_private`. + pub(crate) show_coverage: bool, } impl<'tcx> DocContext<'tcx> { @@ -154,7 +156,8 @@ impl<'tcx> DocContext<'tcx> { pub(crate) fn new_handler( error_format: ErrorOutputType, source_map: Option<Lrc<source_map::SourceMap>>, - debugging_opts: &DebuggingOptions, + diagnostic_width: Option<usize>, + unstable_opts: &UnstableOptions, ) -> rustc_errors::Handler { let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); @@ -168,11 +171,11 @@ pub(crate) fn new_handler( None, fallback_bundle, short, - debugging_opts.teach, - debugging_opts.terminal_width, + unstable_opts.teach, + diagnostic_width, false, ) - .ui_testing(debugging_opts.ui_testing), + .ui_testing(unstable_opts.ui_testing), ) } ErrorOutputType::Json { pretty, json_rendered } => { @@ -187,17 +190,17 @@ pub(crate) fn new_handler( fallback_bundle, pretty, json_rendered, - debugging_opts.terminal_width, + diagnostic_width, false, ) - .ui_testing(debugging_opts.ui_testing), + .ui_testing(unstable_opts.ui_testing), ) } }; rustc_errors::Handler::with_emitter_and_flags( emitter, - debugging_opts.diagnostic_handler_flags(true), + unstable_opts.diagnostic_handler_flags(true), ) } @@ -208,12 +211,13 @@ pub(crate) fn create_config( crate_name, proc_macro_crate, error_format, + diagnostic_width, libs, externs, mut cfgs, check_cfgs, codegen_options, - debugging_opts, + unstable_opts, target, edition, maybe_sysroot, @@ -264,8 +268,9 @@ pub(crate) fn create_config( target_triple: target, unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), actually_rustdoc: true, - debugging_opts, + unstable_opts, error_format, + diagnostic_width, edition, describe_lints, crate_name, @@ -285,7 +290,7 @@ pub(crate) fn create_config( diagnostic_output: DiagnosticOutput::Default, lint_caps, parse_sess_created: None, - register_lints: Some(box crate::lint::register_lints), + register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. providers.lint_mod = |_, _| {}; @@ -378,6 +383,7 @@ pub(crate) fn run_global_ctxt( inlined: FxHashSet::default(), output_format, render_options, + show_coverage, }; // Small hack to force the Sized trait to be present. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index ab72f4a3f502c..568bad2a382c1 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -103,7 +103,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { diagnostic_output: DiagnosticOutput::Default, lint_caps, parse_sess_created: None, - register_lints: Some(box crate::lint::register_lints), + register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), @@ -357,8 +357,8 @@ fn run_test( for codegen_options_str in &rustdoc_options.codegen_options_strs { compiler.arg("-C").arg(&codegen_options_str); } - for debugging_option_str in &rustdoc_options.debugging_opts_strs { - compiler.arg("-Z").arg(&debugging_option_str); + for unstable_option_str in &rustdoc_options.unstable_opts_strs { + compiler.arg("-Z").arg(&unstable_option_str); } if no_run && !lang_string.compile_fail && rustdoc_options.persist_doctests.is_none() { compiler.arg("--emit=metadata"); @@ -556,7 +556,7 @@ pub(crate) fn make_test( .supports_color(); let emitter = EmitterWriter::new( - box io::sink(), + Box::new(io::sink()), None, None, fallback_bundle, @@ -568,7 +568,7 @@ pub(crate) fn make_test( ); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser - let handler = Handler::with_emitter(false, None, box emitter); + let handler = Handler::with_emitter(false, None, Box::new(emitter)); let sess = ParseSess::with_span_handler(handler, sm); let mut found_main = false; @@ -726,31 +726,58 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { // Empty content so nothing to check in here... return true; } - rustc_span::create_session_if_not_set_then(edition, |_| { - let filename = FileName::anon_source_code(source); - let sess = ParseSess::with_silent_emitter(None); - let mut parser = match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) - { - Ok(p) => p, - Err(_) => { - debug!("Cannot build a parser to check mod attr so skipping..."); - return true; + rustc_driver::catch_fatal_errors(|| { + rustc_span::create_session_if_not_set_then(edition, |_| { + use rustc_errors::emitter::EmitterWriter; + use rustc_errors::Handler; + use rustc_span::source_map::FilePathMapping; + + let filename = FileName::anon_source_code(source); + // Any errors in parsing should also appear when the doctest is compiled for real, so just + // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let fallback_bundle = + rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false); + + let emitter = EmitterWriter::new( + box io::sink(), + None, + None, + fallback_bundle, + false, + false, + false, + None, + false, + ); + + let handler = Handler::with_emitter(false, None, box emitter); + let sess = ParseSess::with_span_handler(handler, sm); + let mut parser = + match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) { + Ok(p) => p, + Err(_) => { + debug!("Cannot build a parser to check mod attr so skipping..."); + return true; + } + }; + // If a parsing error happened, it's very likely that the attribute is incomplete. + if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) { + e.cancel(); + return false; } - }; - // If a parsing error happened, it's very likely that the attribute is incomplete. - if parser.parse_attribute(InnerAttrPolicy::Permitted).is_err() { - return false; - } - // We now check if there is an unclosed delimiter for the attribute. To do so, we look at - // the `unclosed_delims` and see if the opening square bracket was closed. - parser - .unclosed_delims() - .get(0) - .map(|unclosed| { - unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2) - }) - .unwrap_or(true) + // We now check if there is an unclosed delimiter for the attribute. To do so, we look at + // the `unclosed_delims` and see if the opening square bracket was closed. + parser + .unclosed_delims() + .get(0) + .map(|unclosed| { + unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2) + }) + .unwrap_or(true) + }) }) + .unwrap_or(false) } fn partition_source(s: &str, edition: Edition) -> (String, String, String) { @@ -1003,8 +1030,10 @@ impl Tester for Collector { let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() { path.push(&test_id); - std::fs::create_dir_all(&path) - .expect("Couldn't create directory for doctest executables"); + if let Err(err) = std::fs::create_dir_all(&path) { + eprintln!("Couldn't create directory for doctest executables: {}", err); + panic::resume_unwind(Box::new(())); + } DirState::Perm(path) } else { @@ -1032,7 +1061,7 @@ impl Tester for Collector { no_run, test_type: test::TestType::DocTest, }, - testfn: test::DynTestFn(box move || { + testfn: test::DynTestFn(Box::new(move || { let report_unused_externs = |uext| { unused_externs.lock().unwrap().push(uext); }; @@ -1103,9 +1132,9 @@ impl Tester for Collector { } } - panic::resume_unwind(box ()); + panic::resume_unwind(Box::new(())); } - }), + })), }); } diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index eca5501cd339d..9cb3327d7c781 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -48,7 +48,6 @@ pub(crate) enum ItemType { ProcAttribute = 23, ProcDerive = 24, TraitAlias = 25, - Generic = 26, } impl Serialize for ItemType { @@ -175,7 +174,6 @@ impl ItemType { ItemType::ProcAttribute => "attr", ItemType::ProcDerive => "derive", ItemType::TraitAlias => "traitalias", - ItemType::Generic => "generic", } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 056eda089c1de..9f46ab54d3ece 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -146,6 +146,10 @@ impl Buffer { pub(crate) fn reserve(&mut self, additional: usize) { self.buffer.reserve(additional) } + + pub(crate) fn len(&self) -> usize { + self.buffer.len() + } } fn comma_sep<T: fmt::Display>( @@ -264,6 +268,12 @@ impl clean::Generics { } } +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) enum Ending { + Newline, + NoNewline, +} + /// * The Generics from which to emit a where-clause. /// * The number of spaces to indent each line with. /// * Whether the where-clause needs to add a comma and newline after the last bound. @@ -271,7 +281,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( gens: &'a clean::Generics, cx: &'a Context<'tcx>, indent: usize, - end_newline: bool, + ending: Ending, ) -> impl fmt::Display + 'a + Captures<'tcx> { use fmt::Write; @@ -338,7 +348,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let where_preds = comma_sep(where_predicates, false); let clause = if f.alternate() { - if end_newline { + if ending == Ending::Newline { // add a space so stripping <br> tags and breaking spaces still renders properly format!(" where{where_preds}, ") } else { @@ -352,7 +362,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( } let where_preds = where_preds.to_string().replace("<br>", &br_with_padding); - if end_newline { + if ending == Ending::Newline { let mut clause = " ".repeat(indent.saturating_sub(1)); // add a space so stripping <br> tags and breaking spaces still renders properly write!( @@ -733,21 +743,23 @@ pub(crate) fn href_relative_parts<'fqp>( if f != r { let dissimilar_part_count = relative_to_fqp.len() - i; let fqp_module = &fqp[i..fqp.len()]; - return box iter::repeat(sym::dotdot) - .take(dissimilar_part_count) - .chain(fqp_module.iter().copied()); + return Box::new( + iter::repeat(sym::dotdot) + .take(dissimilar_part_count) + .chain(fqp_module.iter().copied()), + ); } } // e.g. linking to std::sync::atomic from std::sync if relative_to_fqp.len() < fqp.len() { - box fqp[relative_to_fqp.len()..fqp.len()].iter().copied() + Box::new(fqp[relative_to_fqp.len()..fqp.len()].iter().copied()) // e.g. linking to std::sync from std::sync::atomic } else if fqp.len() < relative_to_fqp.len() { let dissimilar_part_count = relative_to_fqp.len() - fqp.len(); - box iter::repeat(sym::dotdot).take(dissimilar_part_count) + Box::new(iter::repeat(sym::dotdot).take(dissimilar_part_count)) // linking to the same module } else { - box iter::empty() + Box::new(iter::empty()) } } @@ -1163,7 +1175,7 @@ impl clean::Impl { fmt_type(&self.for_, f, use_absolute, cx)?; } - fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, true), f)?; + fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, Ending::Newline), f)?; Ok(()) }) } @@ -1283,10 +1295,6 @@ impl clean::FnDecl { let mut args = Buffer::html(); let mut args_plain = Buffer::new(); for (i, input) in self.inputs.values.iter().enumerate() { - if i == 0 { - args.push_str("<br>"); - } - if let Some(selfty) = input.to_self() { match selfty { clean::SelfValue => { @@ -1312,8 +1320,7 @@ impl clean::FnDecl { } } else { if i > 0 { - args.push_str(" <br>"); - args_plain.push_str(" "); + args.push_str("<br>"); } if input.is_const { args.push_str("const "); @@ -1360,13 +1367,14 @@ impl clean::FnDecl { let full_pad = format!("<br>{}", " ".repeat(indent + 4)); let close_pad = format!("<br>{}", " ".repeat(indent)); format!( - "({args}{close}){arrow}", + "({pad}{args}{close}){arrow}", + pad = if self.inputs.values.is_empty() { "" } else { &full_pad }, args = args.replace("<br>", &full_pad), close = close_pad, arrow = arrow ) } else { - format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow) + format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow) }; if f.alternate() { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 91733004e44c3..4170c73b24625 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1442,7 +1442,6 @@ static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { let mut map = FxHashMap::default(); // This is the list of IDs used in Javascript. - map.insert("help".into(), 1); map.insert("settings".into(), 1); map.insert("not-displayed".into(), 1); map.insert("alternative-display".into(), 1); @@ -1455,7 +1454,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { map.insert("help-button".into(), 1); map.insert("main-content".into(), 1); map.insert("crate-search".into(), 1); - map.insert("render-detail".into(), 1); map.insert("toggle-all-docs".into(), 1); map.insert("all-types".into(), 1); map.insert("default-settings".into(), 1); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index bfdc44c7e4534..2ed7a6f1bb144 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -22,7 +22,7 @@ use super::{ }; use crate::clean::{self, types::ExternalLocation, ExternalCrate}; -use crate::config::RenderOptions; +use crate::config::{ModuleSorting, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::error::Error; use crate::formats::cache::Cache; @@ -95,7 +95,7 @@ pub(crate) struct SharedContext<'tcx> { created_dirs: RefCell<FxHashSet<PathBuf>>, /// This flag indicates whether listings of modules (in the side bar and documentation itself) /// should be ordered alphabetically or in order of appearance (in the source code). - pub(super) sort_modules_alphabetically: bool, + pub(super) module_sorting: ModuleSorting, /// Additional CSS files to be added to the generated docs. pub(crate) style_files: Vec<StylePath>, /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes @@ -280,10 +280,13 @@ impl<'tcx> Context<'tcx> { } } - if self.shared.sort_modules_alphabetically { - for items in map.values_mut() { - items.sort(); + match self.shared.module_sorting { + ModuleSorting::Alphabetical => { + for items in map.values_mut() { + items.sort(); + } } + ModuleSorting::DeclarationOrder => {} } map } @@ -394,7 +397,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { external_html, id_map, playground_url, - sort_modules_alphabetically, + module_sorting, themes: style_files, default_settings, extension_css, @@ -476,7 +479,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { issue_tracker_base_url, layout, created_dirs: Default::default(), - sort_modules_alphabetically, + module_sorting, style_files, resource_suffix, static_root_path, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3f426ee93e77e..c1fdece9ec6da 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -70,7 +70,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ href, join_with_double_colon, print_abi_with_space, print_constness_with_space, - print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, + print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError, PrintWithSpace, }; use crate::html::highlight; @@ -110,63 +110,72 @@ pub(crate) struct IndexItem { /// A type used for the search index. #[derive(Debug)] pub(crate) struct RenderType { - name: Option<String>, - generics: Option<Vec<TypeWithKind>>, + id: Option<RenderTypeId>, + generics: Option<Vec<RenderType>>, } -/// Full type of functions/methods in the search index. -#[derive(Debug)] -pub(crate) struct IndexItemFunctionType { - inputs: Vec<TypeWithKind>, - output: Vec<TypeWithKind>, -} - -impl Serialize for IndexItemFunctionType { +impl Serialize for RenderType { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { - // If we couldn't figure out a type, just write `null`. - let has_missing = self.inputs.iter().chain(self.output.iter()).any(|i| i.ty.name.is_none()); - if has_missing { - serializer.serialize_none() - } else { + let id = match &self.id { + // 0 is a sentinel, everything else is one-indexed + None => 0, + Some(RenderTypeId::Index(idx)) => idx + 1, + _ => panic!("must convert render types to indexes before serializing"), + }; + if let Some(generics) = &self.generics { let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&self.inputs)?; - match self.output.as_slice() { - [] => {} - [one] => seq.serialize_element(one)?, - all => seq.serialize_element(all)?, - } + seq.serialize_element(&id)?; + seq.serialize_element(generics)?; seq.end() + } else { + id.serialize(serializer) } } } -#[derive(Debug)] -pub(crate) struct TypeWithKind { - ty: RenderType, - kind: ItemType, +#[derive(Clone, Debug)] +pub(crate) enum RenderTypeId { + DefId(DefId), + Primitive(clean::PrimitiveType), + Index(usize), } -impl From<(RenderType, ItemType)> for TypeWithKind { - fn from(x: (RenderType, ItemType)) -> TypeWithKind { - TypeWithKind { ty: x.0, kind: x.1 } - } +/// Full type of functions/methods in the search index. +#[derive(Debug)] +pub(crate) struct IndexItemFunctionType { + inputs: Vec<RenderType>, + output: Vec<RenderType>, } -impl Serialize for TypeWithKind { +impl Serialize for IndexItemFunctionType { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&self.ty.name)?; - seq.serialize_element(&self.kind)?; - if let Some(generics) = &self.ty.generics { - seq.serialize_element(generics)?; + // If we couldn't figure out a type, just write `0`. + let has_missing = self + .inputs + .iter() + .chain(self.output.iter()) + .any(|i| i.id.is_none() && i.generics.is_none()); + if has_missing { + 0.serialize(serializer) + } else { + let mut seq = serializer.serialize_seq(None)?; + match &self.inputs[..] { + [one] if one.generics.is_none() => seq.serialize_element(one)?, + _ => seq.serialize_element(&self.inputs)?, + } + match &self.output[..] { + [] => {} + [one] if one.generics.is_none() => seq.serialize_element(one)?, + _ => seq.serialize_element(&self.output)?, + } + seq.end() } - seq.end() } } @@ -625,7 +634,6 @@ fn render_impls( &[], ImplRenderingParameters { show_def_docs: true, - is_on_foreign_type: false, show_default_items: true, show_non_assoc_items: true, toggle_open_by_default, @@ -707,12 +715,14 @@ fn assoc_const( ty = ty.print(cx), ); if let Some(default) = default { + write!(w, " = "); + // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the // hood which adds noisy underscores and a type suffix to number literals. // This hurts readability in this context especially when more complex expressions // are involved and it doesn't add much of value. // Find a way to print constants here without all that jazz. - write!(w, " = {}", default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx()))); + write!(w, "{}", Escape(&default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())))); } } @@ -737,7 +747,7 @@ fn assoc_type( if !bounds.is_empty() { write!(w, ": {}", print_generic_bounds(bounds, cx)) } - write!(w, "{}", print_where_clause(generics, cx, indent, false)); + write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline)); if let Some(default) = default { write!(w, " = {}", default.print(cx)) } @@ -786,10 +796,10 @@ fn assoc_method( header_len += 4; let indent_str = " "; render_attributes_in_pre(w, meth, indent_str); - (4, indent_str, false) + (4, indent_str, Ending::NoNewline) } else { render_attributes_in_code(w, meth); - (0, "", true) + (0, "", Ending::Newline) }; w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len()); write!( @@ -844,7 +854,7 @@ fn render_stability_since_raw( } let const_title_and_stability = match const_stability { - Some(ConstStability { level: StabilityLevel::Stable { since }, .. }) + Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) if Some(since) != containing_const_ver => { Some((format!("const since {}", since), format!("const: {}", since))) @@ -1060,7 +1070,6 @@ fn render_assoc_items_inner( &[], ImplRenderingParameters { show_def_docs: true, - is_on_foreign_type: false, show_default_items: true, show_non_assoc_items: true, toggle_open_by_default: true, @@ -1276,7 +1285,6 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { #[derive(Clone, Copy, Debug)] struct ImplRenderingParameters { show_def_docs: bool, - is_on_foreign_type: bool, show_default_items: bool, /// Whether or not to show methods. show_non_assoc_items: bool, @@ -1404,7 +1412,10 @@ fn render_impl( id, item_type, in_trait_class, ); render_rightside(w, cx, item, containing_item, render_mode); - write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + } w.write_str("<h4 class=\"code-header\">"); render_assoc_item( w, @@ -1427,7 +1438,10 @@ fn render_impl( id, item_type, in_trait_class ); render_rightside(w, cx, item, containing_item, render_mode); - write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + } w.write_str("<h4 class=\"code-header\">"); assoc_const( w, @@ -1449,7 +1463,10 @@ fn render_impl( let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class); - write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + } w.write_str("<h4 class=\"code-header\">"); assoc_type( w, @@ -1472,7 +1489,10 @@ fn render_impl( "<section id=\"{}\" class=\"{}{} has-srclink\">", id, item_type, in_trait_class ); - write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + if trait_.is_some() { + // Anchors are only used on trait impls. + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + } w.write_str("<h4 class=\"code-header\">"); assoc_type( w, @@ -1592,7 +1612,6 @@ fn render_impl( parent, rendering_params.show_def_docs, use_absolute, - rendering_params.is_on_foreign_type, aliases, ); if toggled { @@ -1677,21 +1696,12 @@ pub(crate) fn render_impl_summary( containing_item: &clean::Item, show_def_docs: bool, use_absolute: Option<bool>, - is_on_foreign_type: bool, // This argument is used to reference same type with different paths to avoid duplication // in documentation pages for trait with automatic implementations like "Send" and "Sync". aliases: &[String], ) { - let id = cx.derive_id(match i.inner_impl().trait_ { - Some(ref t) => { - if is_on_foreign_type { - get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx) - } else { - format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx)))) - } - } - None => "impl".to_string(), - }); + let id = + cx.derive_id(get_id_for_impl(&i.inner_impl().for_, i.inner_impl().trait_.as_ref(), cx)); let aliases = if aliases.is_empty() { String::new() } else { @@ -1975,21 +1985,18 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { let mut ret = impls .iter() .filter_map(|it| { - if let Some(ref i) = it.inner_impl().trait_ { - let i_display = format!("{:#}", i.print(cx)); - let out = Escape(&i_display); - let encoded = - id_map.derive(small_url_encode(format!("impl-{:#}", i.print(cx)))); - let prefix = match it.inner_impl().polarity { - ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", - ty::ImplPolarity::Negative => "!", - }; - let generated = - format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out); - if links.insert(generated.clone()) { Some(generated) } else { None } - } else { - None - } + let trait_ = it.inner_impl().trait_.as_ref()?; + let encoded = + id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx)); + + let i_display = format!("{:#}", trait_.print(cx)); + let out = Escape(&i_display); + let prefix = match it.inner_impl().polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", + ty::ImplPolarity::Negative => "!", + }; + let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out); + if links.insert(generated.clone()) { Some(generated) } else { None } }) .collect::<Vec<String>>(); ret.sort(); @@ -2136,12 +2143,11 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea } } -fn get_id_for_impl_on_foreign_type( - for_: &clean::Type, - trait_: &clean::Path, - cx: &Context<'_>, -) -> String { - small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx))) +fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String { + match trait_ { + Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))), + None => small_url_encode(format!("impl-{:#}", for_.print(cx))), + } } fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> { @@ -2150,10 +2156,7 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String i.trait_.as_ref().map(|trait_| { // Alternative format produces no URLs, // so this parameter does nothing. - ( - format!("{:#}", i.for_.print(cx)), - get_id_for_impl_on_foreign_type(&i.for_, trait_, cx), - ) + (format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx)) }) } _ => None, @@ -2517,7 +2520,6 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection { ItemType::ProcAttribute => ItemSection::AttributeMacros, ItemType::ProcDerive => ItemSection::DeriveMacros, ItemType::TraitAlias => ItemSection::TraitAliases, - ItemType::Generic => unreachable!(), } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d115185562ce4..daacc57a55a3a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -23,12 +23,13 @@ use super::{ AssocItemLink, Context, ImplRenderingParameters, }; use crate::clean; +use crate::config::ModuleSorting; 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, - Buffer, PrintWithSpace, + Buffer, Ending, PrintWithSpace, }; use crate::html::highlight; use crate::html::layout::Page; @@ -61,6 +62,17 @@ struct ItemVars<'a> { src_href: Option<&'a str>, } +/// Calls `print_where_clause` and returns `true` if a `where` clause was generated. +fn print_where_clause_and_check<'a, 'tcx: 'a>( + buffer: &mut Buffer, + gens: &'a clean::Generics, + cx: &'a Context<'tcx>, +) -> bool { + let len_before = buffer.len(); + write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline)); + len_before != buffer.len() +} + pub(super) fn print_item( cx: &mut Context<'_>, item: &clean::Item, @@ -246,8 +258,11 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: compare_names(lhs.as_str(), rhs.as_str()) } - if cx.shared.sort_modules_alphabetically { - indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx())); + match cx.shared.module_sorting { + ModuleSorting::Alphabetical => { + indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx())); + } + ModuleSorting::DeclarationOrder => {} } // This call is to remove re-export duplicates in cases such as: // @@ -504,7 +519,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle abi = abi, name = name, generics = f.generics.print(cx), - where_clause = print_where_clause(&f.generics, cx, 0, true), + where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline), decl = f.decl.full_print(header_len, 0, header.asyncness, cx), notable_traits = notable_traits_decl(&f.decl, cx), ); @@ -541,7 +556,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: ); if !t.generics.where_predicates.is_empty() { - write!(w, "{}", print_where_clause(&t.generics, cx, 0, true)); + write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline)); } else { w.write_str(" "); } @@ -849,7 +864,6 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: &[], ImplRenderingParameters { show_def_docs: false, - is_on_foreign_type: true, show_default_items: false, show_non_assoc_items: true, toggle_open_by_default: false, @@ -1011,7 +1025,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: & "trait {}{}{} = {};", it.name.unwrap(), t.generics.print(cx), - print_where_clause(&t.generics, cx, 0, true), + print_where_clause(&t.generics, cx, 0, Ending::Newline), bounds(&t.bounds, true, cx) ); }); @@ -1035,7 +1049,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl "type {}{}{where_clause} = impl {bounds};", it.name.unwrap(), t.generics.print(cx), - where_clause = print_where_clause(&t.generics, cx, 0, true), + where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), bounds = bounds(&t.bounds, false, cx), ); }); @@ -1060,7 +1074,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea "type {}{}{where_clause} = {type_};", it.name.unwrap(), t.generics.print(cx), - where_clause = print_where_clause(&t.generics, cx, 0, true), + where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), type_ = t.type_.print(cx), ); }); @@ -1148,17 +1162,21 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: render_attributes_in_pre(w, it, ""); write!( w, - "{}enum {}{}{}", + "{}enum {}{}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap(), e.generics.print(cx), - print_where_clause(&e.generics, cx, 0, true), ); + if !print_where_clause_and_check(w, &e.generics, cx) { + // If there wasn't a `where` clause, we add a whitespace. + w.write_str(" "); + } + let variants_stripped = e.has_stripped_entries(); if count_variants == 0 && !variants_stripped { - w.write_str(" {}"); + w.write_str("{}"); } else { - w.write_str(" {\n"); + w.write_str("{\n"); let toggle = should_hide_fields(count_variants); if toggle { toggle_open(w, format_args!("{} variants", count_variants)); @@ -1356,6 +1374,15 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle typ = c.type_.print(cx), ); + // FIXME: The code below now prints + // ` = _; // 100i32` + // if the expression is + // `50 + 50` + // which looks just wrong. + // Should we print + // ` = 100i32;` + // instead? + let value = c.value(cx.tcx()); let is_literal = c.is_literal(cx.tcx()); let expr = c.expr(cx.tcx()); @@ -1614,7 +1641,6 @@ fn render_implementor( aliases, ImplRenderingParameters { show_def_docs: false, - is_on_foreign_type: false, show_default_items: false, show_non_assoc_items: false, toggle_open_by_default: false, @@ -1630,13 +1656,21 @@ fn render_union( tab: &str, cx: &Context<'_>, ) { - write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap()); - if let Some(g) = g { - write!(w, "{}", g.print(cx)); - write!(w, "{}", print_where_clause(g, cx, 0, true)); + write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap(),); + + let where_displayed = g + .map(|g| { + write!(w, "{}", g.print(cx)); + print_where_clause_and_check(w, g, cx) + }) + .unwrap_or(false); + + // If there wasn't a `where` clause, we add a whitespace. + if !where_displayed { + w.write_str(" "); } - write!(w, " {{\n{}", tab); + write!(w, "{{\n{}", tab); let count_fields = fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count(); let toggle = should_hide_fields(count_fields); @@ -1688,10 +1722,14 @@ fn render_struct( } match ty { CtorKind::Fictive => { - if let Some(g) = g { - write!(w, "{}", print_where_clause(g, cx, 0, true),) + let where_diplayed = g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); + + // If there wasn't a `where` clause, we add a whitespace. + if !where_diplayed { + w.write_str(" {"); + } else { + w.write_str("{"); } - w.write_str(" {"); let count_fields = fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count(); let has_visible_fields = count_fields > 0; @@ -1746,7 +1784,7 @@ fn render_struct( } w.write_str(")"); if let Some(g) = g { - write!(w, "{}", print_where_clause(g, cx, 0, false),) + write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline)); } // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct. if structhead { @@ -1756,7 +1794,7 @@ fn render_struct( CtorKind::Const => { // Needed for PhantomData. if let Some(g) = g { - write!(w, "{}", print_where_clause(g, cx, 0, false),) + write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline)); } w.write_str(";"); } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 9f302cc256659..d672f0bb5992b 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -3,16 +3,19 @@ use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; -use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate}; +use crate::clean::types::{ + FnRetTy, Function, GenericBound, Generics, ItemId, Type, WherePredicate, +}; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; -use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; +use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; /// Builds the search index from the collected metadata pub(crate) fn build_index<'tcx>( @@ -20,7 +23,7 @@ pub(crate) fn build_index<'tcx>( cache: &mut Cache, tcx: TyCtxt<'tcx>, ) -> String { - let mut defid_to_pathid = FxHashMap::default(); + let mut itemid_to_pathid = FxHashMap::default(); let mut crate_paths = vec![]; // Attach all orphan items to the type's definition if the type @@ -48,14 +51,12 @@ pub(crate) fn build_index<'tcx>( .doc_value() .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(cache))); - let Cache { ref mut search_index, ref paths, .. } = *cache; - // Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, // we need the alias element to have an array of items. let mut aliases: BTreeMap<String, Vec<usize>> = BTreeMap::new(); // Sort search index items. This improves the compressibility of the search index. - search_index.sort_unstable_by(|k1, k2| { + cache.search_index.sort_unstable_by(|k1, k2| { // `sort_unstable_by_key` produces lifetime errors let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent); let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent); @@ -63,7 +64,7 @@ pub(crate) fn build_index<'tcx>( }); // Set up alias indexes. - for (i, item) in search_index.iter().enumerate() { + for (i, item) in cache.search_index.iter().enumerate() { for alias in &item.aliases[..] { aliases.entry(alias.as_str().to_lowercase()).or_default().push(i); } @@ -74,24 +75,99 @@ pub(crate) fn build_index<'tcx>( let mut lastpath = ""; let mut lastpathid = 0usize; + // First, on function signatures + let mut search_index = std::mem::replace(&mut cache.search_index, Vec::new()); + for item in search_index.iter_mut() { + fn convert_render_type( + ty: &mut RenderType, + cache: &mut Cache, + itemid_to_pathid: &mut FxHashMap<ItemId, usize>, + lastpathid: &mut usize, + crate_paths: &mut Vec<(ItemType, Symbol)>, + ) { + if let Some(generics) = &mut ty.generics { + for item in generics { + convert_render_type(item, cache, itemid_to_pathid, lastpathid, crate_paths); + } + } + let Cache { ref paths, ref external_paths, .. } = *cache; + let Some(id) = ty.id.clone() else { + assert!(ty.generics.is_some()); + return; + }; + let (itemid, path, item_type) = match id { + RenderTypeId::DefId(defid) => { + if let Some(&(ref fqp, item_type)) = + paths.get(&defid).or_else(|| external_paths.get(&defid)) + { + (ItemId::DefId(defid), *fqp.last().unwrap(), item_type) + } else { + ty.id = None; + return; + } + } + RenderTypeId::Primitive(primitive) => ( + ItemId::Primitive(primitive, LOCAL_CRATE), + primitive.as_sym(), + ItemType::Primitive, + ), + RenderTypeId::Index(_) => return, + }; + match itemid_to_pathid.entry(itemid) { + Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())), + Entry::Vacant(entry) => { + let pathid = *lastpathid; + entry.insert(pathid); + *lastpathid += 1; + crate_paths.push((item_type, path)); + ty.id = Some(RenderTypeId::Index(pathid)); + } + } + } + if let Some(search_type) = &mut item.search_type { + for item in &mut search_type.inputs { + convert_render_type( + item, + cache, + &mut itemid_to_pathid, + &mut lastpathid, + &mut crate_paths, + ); + } + for item in &mut search_type.output { + convert_render_type( + item, + cache, + &mut itemid_to_pathid, + &mut lastpathid, + &mut crate_paths, + ); + } + } + } + + let Cache { ref paths, .. } = *cache; + + // Then, on parent modules let crate_items: Vec<&IndexItem> = search_index .iter_mut() .map(|item| { - item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) { - Entry::Occupied(entry) => Some(*entry.get()), - Entry::Vacant(entry) => { - let pathid = lastpathid; - entry.insert(pathid); - lastpathid += 1; + item.parent_idx = + item.parent.and_then(|defid| match itemid_to_pathid.entry(ItemId::DefId(defid)) { + Entry::Occupied(entry) => Some(*entry.get()), + Entry::Vacant(entry) => { + let pathid = lastpathid; + entry.insert(pathid); + lastpathid += 1; - if let Some(&(ref fqp, short)) = paths.get(&defid) { - crate_paths.push((short, *fqp.last().unwrap())); - Some(pathid) - } else { - None + if let Some(&(ref fqp, short)) = paths.get(&defid) { + crate_paths.push((short, *fqp.last().unwrap())); + Some(pathid) + } else { + None + } } - } - }); + }); // Omit the parent path if it is same to that of the prior item. if lastpath == &item.path { @@ -151,13 +227,40 @@ pub(crate) fn build_index<'tcx>( "`{}` is missing idx", item.name ); + // 0 is a sentinel, everything else is one-indexed item.parent_idx.map(|x| x + 1).unwrap_or(0) }) .collect::<Vec<_>>(), )?; crate_data.serialize_field( "f", - &self.items.iter().map(|item| &item.search_type).collect::<Vec<_>>(), + &self + .items + .iter() + .map(|item| { + // Fake option to get `0` out as a sentinel instead of `null`. + // We want to use `0` because it's three less bytes. + enum FunctionOption<'a> { + Function(&'a IndexItemFunctionType), + None, + } + impl<'a> Serialize for FunctionOption<'a> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self { + FunctionOption::None => 0.serialize(serializer), + FunctionOption::Function(ty) => ty.serialize(serializer), + } + } + } + match &item.search_type { + Some(ty) => FunctionOption::Function(ty), + None => FunctionOption::None, + } + }) + .collect::<Vec<_>>(), )?; crate_data.serialize_field( "p", @@ -202,36 +305,33 @@ pub(crate) fn get_function_type_for_search<'tcx>( _ => return None, }; - inputs.retain(|a| a.ty.name.is_some()); - output.retain(|a| a.ty.name.is_some()); + inputs.retain(|a| a.id.is_some() || a.generics.is_some()); + output.retain(|a| a.id.is_some() || a.generics.is_some()); Some(IndexItemFunctionType { inputs, output }) } -fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType { +fn get_index_type(clean_type: &clean::Type, generics: Vec<RenderType>) -> RenderType { RenderType { - name: get_index_type_name(clean_type).map(|s| s.as_str().to_ascii_lowercase()), + id: get_index_type_id(clean_type), generics: if generics.is_empty() { None } else { Some(generics) }, } } -fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> { +fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> { match *clean_type { - clean::Type::Path { ref path, .. } => { - let path_segment = path.segments.last().unwrap(); - Some(path_segment.name) - } + clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())), clean::DynTrait(ref bounds, _) => { let path = &bounds[0].trait_; - Some(path.segments.last().unwrap().name) + Some(RenderTypeId::DefId(path.def_id())) } - // We return an empty name because we don't care about the generic name itself. - clean::Generic(_) | clean::ImplTrait(_) => Some(kw::Empty), - clean::Primitive(ref p) => Some(p.as_sym()), + clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => { - get_index_type_name(type_) + get_index_type_id(type_) } clean::BareFunction(_) + | clean::Generic(_) + | clean::ImplTrait(_) | clean::Tuple(_) | clean::Slice(_) | clean::Array(_, _) @@ -254,16 +354,10 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( arg: &'a Type, tcx: TyCtxt<'tcx>, recurse: usize, - res: &mut Vec<TypeWithKind>, + res: &mut Vec<RenderType>, cache: &Cache, ) { - fn insert_ty( - res: &mut Vec<TypeWithKind>, - tcx: TyCtxt<'_>, - ty: Type, - mut generics: Vec<TypeWithKind>, - cache: &Cache, - ) { + fn insert_ty(res: &mut Vec<RenderType>, ty: Type, mut generics: Vec<RenderType>) { // generics and impl trait are both identified by their generics, // rather than a type name itself let anonymous = ty.is_full_generic() || ty.is_impl_trait(); @@ -316,20 +410,11 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( return; } } - let mut index_ty = get_index_type(&ty, generics); - if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) { + let index_ty = get_index_type(&ty, generics); + if index_ty.id.is_none() && generics_empty { return; } - if anonymous { - // We remove the name of the full generic because we have no use for it. - index_ty.name = Some(String::new()); - res.push(TypeWithKind::from((index_ty, ItemType::Generic))); - } else if let Some(kind) = ty.def_id(cache).map(|did| tcx.def_kind(did).into()) { - res.push(TypeWithKind::from((index_ty, kind))); - } else if ty.is_primitive() { - // This is a primitive, let's store it as such. - res.push(TypeWithKind::from((index_ty, ItemType::Primitive))); - } + res.push(index_ty); } if recurse >= 10 { @@ -379,7 +464,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( } } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, arg.clone(), ty_generics); } // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`... if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { @@ -398,7 +483,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( ); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, arg.clone(), ty_generics); } } else if let Type::ImplTrait(ref bounds) = *arg { let mut ty_generics = Vec::new(); @@ -416,7 +501,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( ); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, arg.clone(), ty_generics); } else { // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't. @@ -437,7 +522,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( ); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, arg.clone(), ty_generics); } } @@ -450,7 +535,7 @@ fn get_fn_inputs_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, impl_generics: Option<&(clean::Type, clean::Generics)>, cache: &Cache, -) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) { +) -> (Vec<RenderType>, Vec<RenderType>) { let decl = &func.decl; let combined_generics; @@ -478,9 +563,7 @@ fn get_fn_inputs_and_outputs<'tcx>( if !args.is_empty() { all_types.extend(args); } else { - if let Some(kind) = arg.type_.def_id(cache).map(|did| tcx.def_kind(did).into()) { - all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind))); - } + all_types.push(get_index_type(&arg.type_, vec![])); } } @@ -497,9 +580,7 @@ fn get_fn_inputs_and_outputs<'tcx>( cache, ); if ret_types.is_empty() { - if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) { - ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind))); - } + ret_types.push(get_index_type(return_type, vec![])); } } _ => {} diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index 2817a8fe14488..fcd925bb3582f 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -91,5 +91,6 @@ module.exports = { "no-script-url": "error", "no-sequences": "error", "no-throw-literal": "error", + "no-div-regex": "error", } }; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b4b7790eebba1..c6933a8254bc2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -114,6 +114,9 @@ body { -webkit-font-feature-settings: "kern", "liga"; -moz-font-feature-settings: "kern", "liga"; font-feature-settings: "kern", "liga"; + + background-color: var(--main-background-color); + color: var(--main-color); } h1 { @@ -138,6 +141,10 @@ h1, h2, h3, h4 { h1.fqn { margin: 0; padding: 0; + border-bottom-color: var(--headings-border-bottom-color); +} +h2, h3, h4 { + border-bottom-color: var(--headings-border-bottom-color); } .main-heading { display: flex; @@ -158,8 +165,8 @@ h1.fqn { Underlines elsewhere in the documentation break up visual flow and tend to invert section hierarchies. */ h2, -.top-doc h3, -.top-doc h4 { +.top-doc .docblock > h3, +.top-doc .docblock > h4 { border-bottom: 1px solid; } h3.code-header { @@ -214,6 +221,26 @@ a.srclink, font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif; } +h1, h2, h3, h4, +a#toggle-all-docs, +a.anchor, +.small-section-header a, +#source-sidebar a, +pre.rust a, +.sidebar h2 a, +.sidebar h3 a, +.mobile-topbar h2 a, +.in-band a, +.search-results a, +.module-item .stab, +.import-item .stab, +.result-name .primitive > i, .result-name .keyword > i, +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + color: var(--main-color); +} + ol, ul { padding-left: 24px; } @@ -354,6 +381,10 @@ nav.sub { object-fit: contain; } +.sidebar, .mobile-topbar, .sidebar-menu-toggle { + background-color: var(--sidebar-background-color); +} + .sidebar { font-size: 0.875rem; width: 250px; @@ -391,6 +422,14 @@ nav.sub { display: none; } +.source .sidebar, #sidebar-toggle, #source-sidebar { + background-color: var(--sidebar-background-color); +} + +#sidebar-toggle > button:hover, #sidebar-toggle > button:focus { + background-color: var(--sidebar-background-color-hover); +} + .source .sidebar > *:not(#sidebar-toggle) { opacity: 0; visibility: hidden; @@ -412,9 +451,11 @@ nav.sub { /* Improve the scrollbar display on firefox */ * { scrollbar-width: initial; + scrollbar-color: var(--scrollbar-color); } .sidebar { scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color); } /* Improve the scrollbar display on webkit-based browsers */ @@ -426,6 +467,13 @@ nav.sub { } ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0; + background-color: var(--scrollbar-track-background-color); +} +.sidebar::-webkit-scrollbar-track { + background-color: var(--scrollbar-track-background-color); +} +::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-thumb-background-color); } /* Everything else */ @@ -606,6 +654,9 @@ h2.location a { .docblock h5 { font-size: 1rem; } .docblock h6 { font-size: 0.875rem; } +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { + border-bottom-color: var(--headings-border-bottom-color); +} .docblock { margin-left: 24px; @@ -629,11 +680,6 @@ h2.location a { display: block; } -.invisible { - width: 100%; - display: inline-block; -} - .content .in-band { flex-grow: 1; margin: 0px; @@ -646,6 +692,11 @@ h2.location a { display: inline-block; } +.docblock code, .docblock-short code, +pre, .rustdoc.source .example-wrap { + background-color: var(--code-block-background-color); +} + #main-content { position: relative; } @@ -898,7 +949,6 @@ table, #crate-search { min-width: 115px; margin-top: 5px; - margin-left: 0.25em; padding-left: 0.3125em; padding-right: 23px; border: 1px solid; @@ -915,6 +965,8 @@ table, background-size: 20px; background-position: calc(100% - 1px) 56%; background-image: /* AUTOREPLACE: */url("down-arrow.svg"); + max-width: 100%; + text-overflow: ellipsis; } .search-container { margin-top: 4px; @@ -983,42 +1035,56 @@ table, font-weight: normal; } -body.blur > :not(#help) { - filter: blur(8px); - -webkit-filter: blur(8px); - opacity: .7; +.popover { + font-size: 1rem; + position: absolute; + right: 0; + z-index: 2; + display: block; + margin-top: 7px; + border-radius: 3px; + border: 1px solid; + font-size: 1rem; } -#help { - width: 100%; - height: 100vh; - position: fixed; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; +/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ +.popover::before { + content: ''; + position: absolute; + right: 11px; + border: solid; + border-width: 1px 1px 0 0; + display: inline-block; + padding: 4px; + transform: rotate(-45deg); + top: -5px; } -#help > div { - flex: 0 0 auto; - box-shadow: 0 0 6px rgba(0,0,0,.2); - width: 550px; - height: auto; - border: 1px solid; + +.popover, .popover::before { + background-color: var(--main-background-color); + color: var(--main-color); } -#help dt { + +#help-button .popover { + max-width: 600px; +} + +#help-button .popover::before { + right: 48px; +} + +#help-button dt { float: left; clear: left; display: block; margin-right: 0.5rem; } -#help span.top, #help span.bottom { +#help-button span.top, #help-button span.bottom { text-align: center; display: block; font-size: 1.125rem; - } -#help span.top { +#help-button span.top { text-align: center; display: block; margin: 10px 0; @@ -1026,17 +1092,17 @@ body.blur > :not(#help) { padding-bottom: 4px; margin-bottom: 6px; } -#help span.bottom { +#help-button span.bottom { clear: both; border-top: 1px solid; } -#help dd { margin: 5px 35px; } -#help .infos { padding-left: 0; } -#help h1, #help h2 { margin-top: 0; } -#help > div div { +.side-by-side { + text-align: initial; +} +.side-by-side > div { width: 50%; float: left; - padding: 0 20px 20px 17px;; + padding: 0 20px 20px 17px; } .item-info .stab { @@ -1361,7 +1427,6 @@ pre.rust { position: sticky; top: 0; left: 0; - cursor: pointer; font-weight: bold; font-size: 1.25rem; border-bottom: 1px solid; @@ -1382,7 +1447,24 @@ pre.rust { border-bottom: 1px solid; margin-bottom: 6px; } - +#sidebar-toggle > button { + background: none; + color: inherit; + cursor: pointer; + text-align: center; + border: none; + outline: none; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + /* work around button layout strangeness: https://stackoverflow.com/q/7271561 */ + width: 100%; + /* iOS button gradient: https://stackoverflow.com/q/5438567 */ + -webkit-appearance: none; + opacity: 1; +} #settings-menu, #help-button { margin-left: 4px; outline: none; @@ -1391,7 +1473,7 @@ pre.rust { #copy-path { height: 34px; } -#settings-menu > a, #help-button, #copy-path { +#settings-menu > a, #help-button > button, #copy-path { padding: 5px; width: 33px; border: 1px solid; @@ -1401,9 +1483,8 @@ pre.rust { #settings-menu { padding: 0; } -#settings-menu > a { +#settings-menu > a, #help-button > button { padding: 5px; - width: 100%; height: 100%; display: block; } @@ -1420,7 +1501,26 @@ pre.rust { animation: rotating 2s linear infinite; } -#help-button { +.setting-line .radio-line input:checked { + box-shadow: inset 0 0 0 3px var(--main-background-color); + background-color: var(--settings-input-color); +} +.setting-line .radio-line input:focus { + box-shadow: 0 0 1px 1px var(--settings-input-color); +} +/* In here we combine both `:focus` and `:checked` properties. */ +.setting-line .radio-line input:checked:focus { + box-shadow: inset 0 0 0 3px var(--main-background-color), + 0 0 2px 2px var(--settings-input-color); +} +.setting-line .radio-line input:hover { + border-color: var(--settings-input-color) !important; +} +input:checked + .slider { + background-color: var(--settings-input-color); +} + +#help-button > button { font-family: "Fira Sans", Arial, sans-serif; text-align: center; /* Rare exception to specifying font sizes in rem. Since this is acting @@ -1520,38 +1620,23 @@ kbd { margin-bottom: 1em; } -div.children { - padding-left: 27px; - display: none; +details.dir-entry { + padding-left: 4px; } -div.name { + +details.dir-entry > summary { + margin: 0 0 0 13px; + list-style-position: outside; cursor: pointer; - position: relative; - margin-left: 16px; } -div.files > a { - display: block; - padding: 0 3px; -} -div.files > a:hover, div.name:hover { - background-color: #a14b4b; + +details.dir-entry div.folders, details.dir-entry div.files { + padding-left: 23px; } -div.name.expand + .children { + +details.dir-entry a { display: block; } -div.name::before { - content: "\25B6"; - padding-left: 4px; - font-size: 0.625rem; - position: absolute; - left: -16px; - top: 4px; -} -div.name.expand::before { - transform: rotate(90deg); - left: -15px; - top: 2px; -} /* The hideme class is used on summary tags that contain a span with placeholder text shown only when the toggle is closed. For instance, @@ -1648,13 +1733,12 @@ details.rustdoc-toggle[open] > summary.hideme > span { display: none; } -details.undocumented[open] > summary::before, details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle[open] > summary.hideme::before { background-image: /* AUTOREPLACE: */url("toggle-minus.svg"); } -details.undocumented > summary::before, details.rustdoc-toggle > summary::before { +details.rustdoc-toggle > summary::before { background-image: /* AUTOREPLACE: */url("toggle-plus.svg"); } @@ -1673,8 +1757,18 @@ details.rustdoc-toggle[open] > summary.hideme::after { content: "Collapse"; } +/* This is needed in docblocks to have the "▶" element to be on the same line. */ +.docblock summary > * { + display: inline-block; +} + /* Media Queries */ +/* +WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY; +If you update this line, then you also need to update the line with the same warning +in storage.js plus the media query with (max-width: 700px) +*/ @media (min-width: 701px) { /* In case there is no documentation before a code block, we need to add some margin at the top to prevent an overlay between the "collapse toggle" and the information tooltip. @@ -1695,6 +1789,11 @@ details.rustdoc-toggle[open] > summary.hideme::after { } } +/* +WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +If you update this line, then you also need to update the line with the same warning +in storage.js plus the media query with (min-width: 701px) +*/ @media (max-width: 700px) { /* When linking to an item with an `id` (for instance, by clicking a link in the sidebar, or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured @@ -1764,9 +1863,11 @@ details.rustdoc-toggle[open] > summary.hideme::after { /* The source view uses a different design for the sidebar toggle, and doesn't have a topbar, so don't bump down the main content or the sidebar. */ .source main, - .source .sidebar { + .rustdoc.source .sidebar { top: 0; padding: 0; + height: 100vh; + border: 0; } .sidebar.shown, @@ -1837,6 +1938,10 @@ details.rustdoc-toggle[open] > summary.hideme::after { border: none; } + .sidebar-elems { + background-color: var(--sidebar-background-color); + } + .source nav:not(.sidebar).sub { margin-left: 32px; } @@ -1916,6 +2021,9 @@ details.rustdoc-toggle[open] > summary.hideme::after { width: unset; border-top-right-radius: unset; border-bottom-right-radius: unset; + position: sticky; + border: 0; + border-bottom: 1px solid; } #source-sidebar { @@ -1977,9 +2085,19 @@ details.rustdoc-toggle[open] > summary.hideme::after { } @media print { - nav.sub, .content .out-of-band { + nav.sidebar, nav.sub, .content .out-of-band, a.srclink, #copy-path, + details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before, + details.rustdoc-toggle.top-doc > summary { display: none; } + + .docblock { + margin-left: 0; + } + + main { + padding: 10px; + } } @media (max-width: 464px) { diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 1cd8e39e03648..e531e6ce6bbde 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -86,27 +86,6 @@ input:checked + .slider:before { display: block; } -div#settings { - position: absolute; - right: 0; - z-index: 1; - display: block; - margin-top: 7px; - border-radius: 3px; - border: 1px solid; -} #settings .setting-line { margin: 1.2em 0.6em; } -/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ -div#settings::before { - content: ''; - position: absolute; - right: 11px; - border: solid; - border-width: 1px 1px 0 0; - display: inline-block; - padding: 4px; - transform: rotate(-45deg); - top: -5px; -} diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 8e0521d9ad6a1..142ce456c5213 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -3,30 +3,17 @@ Based off of the Ayu theme Original by Dempfi (https://github.com/dempfi/ayu) */ -/* General structure and fonts */ - -body, #settings-menu #settings, #settings-menu #settings::before { - background-color: #0f1419; - color: #c5c5c5; -} - -.setting-line .radio-line input { - border-color: #c5c5c5; -} -.setting-line .radio-line input:checked { - box-shadow: inset 0 0 0 3px #0f1419; - background-color: #ffb454; -} -.setting-line .radio-line input:focus { - box-shadow: 0 0 1px 1px #ffb454; -} -/* In here we combine both `:focus` and `:checked` properties. */ -.setting-line .radio-line input:checked:focus { - box-shadow: inset 0 0 0 3px 0f1419, - 0 0 2px 2px #ffb454; -} -.setting-line .radio-line input:hover { - border-color: #ffb454 !important; +:root { + --main-background-color: #0f1419; + --main-color: #c5c5c5; + --settings-input-color: #ffb454; + --sidebar-background-color: #14191f; + --sidebar-background-color-hover: rgba(70, 70, 70, 0.33); + --code-block-background-color: #191f26; + --scrollbar-track-background-color: transparent; + --scrollbar-thumb-background-color: #5c6773; + --scrollbar-color: #5c6773 #24292f; + --headings-border-bottom-color: #5c6773; } .slider { @@ -35,9 +22,6 @@ body, #settings-menu #settings, #settings-menu #settings::before { .slider:before { background-color: white; } -input:checked + .slider { - background-color: #ffb454; -} input:focus + .slider { box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3); } @@ -45,15 +29,9 @@ input:focus + .slider { h1, h2, h3, h4 { color: white; } -h1.fqn { - border-bottom-color: #5c6773; -} h1.fqn a { color: #fff; } -h2, h3, h4 { - border-bottom-color: #5c6773; -} h4 { border: none; } @@ -62,10 +40,6 @@ h4 { background-color: #0f1419; } -.invisible { - background: rgba(0, 0, 0, 0); -} - .docblock code { color: #ffb454; } @@ -81,16 +55,8 @@ span code { .docblock a > code { color: #39AFD7 !important; } -.docblock code, .docblock-short code { - background-color: #191f26; -} pre, .rustdoc.source .example-wrap { color: #e6e1cf; - background-color: #191f26; -} - -.sidebar, .mobile-topbar, .sidebar-menu-toggle { - background-color: #14191f; } .rust-logo { @@ -100,39 +66,12 @@ pre, .rustdoc.source .example-wrap { drop-shadow(0 -1px 0 #fff); } -/* Improve the scrollbar display on firefox */ -* { - scrollbar-color: #5c6773 #24292f; -} - -.sidebar { - scrollbar-color: #5c6773 #24292f; -} - -/* Improve the scrollbar display on webkit-based browsers */ -::-webkit-scrollbar-track { - background-color: transparent; -} -::-webkit-scrollbar-thumb { - background-color: #5c6773; -} -.sidebar::-webkit-scrollbar-track { - background-color: transparent; -} -.sidebar::-webkit-scrollbar-thumb { - background-color: #5c6773; -} - .sidebar .current, .sidebar a:hover { background-color: transparent; color: #ffb44c; } -.source .sidebar { - background-color: #14191f; -} - .sidebar-elems .location { color: #ff7733; } @@ -145,20 +84,10 @@ pre, .rustdoc.source .example-wrap { border-right: 1px solid #ffb44c; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { - border-bottom-color: #5c6773; -} - .docblock table td, .docblock table th { border-color: #5c6773; } -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { - color: #c5c5c5; -} - .search-results a:hover { background-color: #777; } @@ -233,17 +162,6 @@ a { color: #39AFD7; } -a#toggle-all-docs, -a.anchor, -.small-section-header a, -#source-sidebar a, -pre.rust a, -.sidebar h2 a, -.sidebar h3 a, -.mobile-topbar h2 a, -.in-band a { - color: #c5c5c5; -} .sidebar h2 a, .sidebar h3 a { color: white; @@ -256,13 +174,11 @@ body.source .example-wrap pre.rust a { } details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before, -details.undocumented > summary::before { +details.rustdoc-toggle > summary::before { color: #999; } -details.rustdoc-toggle > summary::before, -details.undocumented > summary::before { +details.rustdoc-toggle > summary::before { filter: invert(100%); } @@ -300,17 +216,6 @@ details.undocumented > summary::before { background: none; } -#help > div { - background: #14191f; - box-shadow: 0px 6px 20px 0px black; - border: none; - border-radius: 4px; -} - -#help span.bottom, #help span.top { - border-color: #5c6773; -} - .rightside, .out-of-band { color: grey; @@ -542,21 +447,9 @@ a.result-keyword:focus {} .sidebar a.current.keyword {} @media (max-width: 700px) { - .sidebar-menu { - background-color: #14191f; - border-bottom-color: #5c6773; - border-right-color: #5c6773; - } - .sidebar-elems { - background-color: #14191f; border-right-color: #5c6773; } - - #sidebar-filler { - background-color: #14191f; - border-bottom-color: #5c6773; - } } kbd { @@ -567,7 +460,7 @@ kbd { box-shadow: inset 0 -1px 0 #5c6773; } -#settings-menu > a, #help-button { +#settings-menu > a, #help-button > button { border-color: #5c6773; background-color: #0f1419; color: #fff; @@ -577,7 +470,8 @@ kbd { filter: invert(100); } -#settings-menu #settings, #settings-menu #settings::before { +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { border-color: #5c6773; } @@ -592,7 +486,7 @@ kbd { } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button:hover, #help-button:focus { +#help-button > button:hover, #help-button > button:focus { border-color: #e0e0e0; } @@ -616,24 +510,16 @@ kbd { color: #999; } -#sidebar-toggle { - background-color: #14191f; -} -#sidebar-toggle:hover { - background-color: rgba(70, 70, 70, 0.33); -} -#source-sidebar { - background-color: #14191f; -} #source-sidebar > .title { color: #fff; border-bottom-color: #5c6773; } -div.files > a:hover, div.name:hover { +#source-sidebar div.files > a:hover, details.dir-entry summary:hover, +#source-sidebar div.files > a:focus, details.dir-entry summary:focus { background-color: #14191f; color: #ffb44c; } -div.files > .selected { +#source-sidebar div.files > a.selected { background-color: #14191f; color: #ffb44c; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 071ad006ed350..aeaca7515f962 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -1,25 +1,14 @@ -body, #settings-menu #settings, #settings-menu #settings::before { - background-color: #353535; - color: #ddd; -} - -.setting-line .radio-line input { - border-color: #ddd; -} -.setting-line .radio-line input:checked { - box-shadow: inset 0 0 0 3px #353535; - background-color: #2196f3; -} -.setting-line .radio-line input:focus { - box-shadow: 0 0 1px 1px #2196f3; -} -/* In here we combine both `:focus` and `:checked` properties. */ -.setting-line .radio-line input:checked:focus { - box-shadow: inset 0 0 0 3px #353535, - 0 0 2px 2px #2196f3; -} -.setting-line .radio-line input:hover { - border-color: #2196f3 !important; +:root { + --main-background-color: #353535; + --main-color: #ddd; + --settings-input-color: #2196f3; + --sidebar-background-color: #505050; + --sidebar-background-color-hover: #676767; + --code-block-background-color: #2A2A2A; + --scrollbar-track-background-color: #717171; + --scrollbar-thumb-background-color: rgba(32, 34, 37, .6); + --scrollbar-color: rgba(32,34,37,.6) #5a5a5a; + --headings-border-bottom-color: #d2d2d2; } .slider { @@ -28,42 +17,14 @@ body, #settings-menu #settings, #settings-menu #settings::before { .slider:before { background-color: white; } -input:checked + .slider { - background-color: #2196F3; -} input:focus + .slider { box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3); } -h1, h2, h3, h4 { - color: #ddd; -} -h1.fqn { - border-bottom-color: #d2d2d2; -} -h2, h3, h4 { - border-bottom-color: #d2d2d2; -} - .in-band { background-color: #353535; } -.invisible { - background: rgba(0, 0, 0, 0); -} - -.docblock code, .docblock-short code { - background-color: #2A2A2A; -} -pre, .rustdoc.source .example-wrap { - background-color: #2A2A2A; -} - -.sidebar, .mobile-topbar, .sidebar-menu-toggle { - background-color: #505050; -} - .rust-logo { filter: drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) @@ -71,37 +32,11 @@ pre, .rustdoc.source .example-wrap { drop-shadow(0 -1px 0 #fff) } -/* Improve the scrollbar display on firefox */ -* { - scrollbar-color: rgb(64, 65, 67) #717171; -} -.sidebar { - scrollbar-color: rgba(32,34,37,.6) #5a5a5a; -} - -/* Improve the scrollbar display on webkit-based browsers */ -::-webkit-scrollbar-track { - background-color: #717171; -} -::-webkit-scrollbar-thumb { - background-color: rgba(32, 34, 37, .6); -} -.sidebar::-webkit-scrollbar-track { - background-color: #717171; -} -.sidebar::-webkit-scrollbar-thumb { - background-color: rgba(32, 34, 37, .6); -} - .sidebar .current, .sidebar a:hover { background: #444; } -.source .sidebar { - background-color: #565656; -} - .line-numbers span { color: #3B91E2; } .line-numbers .line-highlighted { background-color: #0a042f !important; @@ -115,12 +50,6 @@ pre, .rustdoc.source .example-wrap { border-color: #ddd; } -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { - color: #ddd; -} - .search-results a:hover { background-color: #777; } @@ -214,35 +143,16 @@ a { color: #D2991D; } -a#toggle-all-docs, -a.anchor, -.small-section-header a, -#source-sidebar a, -pre.rust a, -.sidebar h2 a, -.sidebar h3 a, -.mobile-topbar h2 a, -.in-band a { - color: #ddd; -} -.search-results a { - color: #ddd; -} -a.test-arrow { - color: #dedede; -} body.source .example-wrap pre.rust a { background: #333; } details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before, -details.undocumented > summary::before { +details.rustdoc-toggle > summary::before { color: #999; } -details.rustdoc-toggle > summary::before, -details.undocumented > summary::before { +details.rustdoc-toggle > summary::before { filter: invert(100%); } @@ -261,40 +171,17 @@ details.undocumented > summary::before { border-color: #008dfd; } -.module-item .stab, -.import-item .stab { - color: #ddd; -} - .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; } .stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } .stab.portability > code { background: none; } -#help > div { - background: #4d4d4d; - border-color: #bfbfbf; -} - -#help span.bottom, #help span.top { - border-color: #bfbfbf; -} - -#help dt { - border-color: #bfbfbf; - background: rgba(0,0,0,0); -} - .rightside, .out-of-band { color: grey; } -.result-name .primitive > i, .result-name .keyword > i { - color: #ddd; -} - .line-numbers :target { background-color: transparent; } /* Code highlighting */ @@ -314,6 +201,7 @@ pre.rust .question-mark { } a.test-arrow { + color: #dedede; background-color: rgba(78, 139, 202, 0.2); } @@ -417,21 +305,9 @@ pre.ignore:hover, .information:hover + pre.ignore { } @media (max-width: 700px) { - .sidebar-menu { - background-color: #505050; - border-bottom-color: #e0e0e0; - border-right-color: #e0e0e0; - } - .sidebar-elems { - background-color: #505050; border-right-color: #000; } - - #sidebar-filler { - background-color: #505050; - border-bottom-color: #e0e0e0; - } } kbd { @@ -442,18 +318,19 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#settings-menu > a, #help-button { +#settings-menu > a, #help-button > button { border-color: #e0e0e0; background: #f0f0f0; color: #000; } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button:hover, #help-button:focus { +#help-button > button:hover, #help-button > button:focus { border-color: #ffb900; } -#settings-menu #settings, #settings-menu #settings::before { +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { border-color: #d2d2d2; } @@ -487,22 +364,14 @@ kbd { color: #ccc; } -#sidebar-toggle { - background-color: #565656; -} -#sidebar-toggle:hover { - background-color: #676767; -} -#source-sidebar { - background-color: #565656; -} #source-sidebar > .title { border-bottom-color: #ccc; } -div.files > a:hover, div.name:hover { +#source-sidebar div.files > a:hover, details.dir-entry summary:hover, +#source-sidebar div.files > a:focus, details.dir-entry summary:focus { background-color: #444; } -div.files > .selected { +#source-sidebar div.files > a.selected { background-color: #333; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 5c3789bf4630a..54d1a7b65d665 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -1,27 +1,14 @@ -/* General structure and fonts */ - -body, #settings-menu #settings, #settings-menu #settings::before { - background-color: white; - color: black; -} - -.setting-line .radio-line input { - border-color: black; -} -.setting-line .radio-line input:checked { - box-shadow: inset 0 0 0 3px white; - background-color: #2196f3; -} -.setting-line .radio-line input:focus { - box-shadow: 0 0 1px 1px #2196f3; -} -/* In here we combine both `:focus` and `:checked` properties. */ -.setting-line .radio-line input:checked:focus { - box-shadow: inset 0 0 0 3px white, - 0 0 2px 2px #2196f3; -} -.setting-line .radio-line input:hover { - border-color: #2196f3 !important; +:root { + --main-background-color: white; + --main-color: black; + --settings-input-color: #2196f3; + --sidebar-background-color: #F5F5F5; + --sidebar-background-color-hover: #E0E0E0; + --code-block-background-color: #F5F5F5; + --scrollbar-track-background-color: #dcdcdc; + --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6); + --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; + --headings-border-bottom-color: #ddd; } .slider { @@ -30,99 +17,34 @@ body, #settings-menu #settings, #settings-menu #settings::before { .slider:before { background-color: white; } -input:checked + .slider { - background-color: #2196F3; -} input:focus + .slider { box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3); } -h1, h2, h3, h4 { - color: black; -} -h1.fqn { - border-bottom-color: #DDDDDD; -} -h2, h3, h4 { - border-bottom-color: #DDDDDD; -} - .in-band { background-color: white; } -.invisible { - background: rgba(0, 0, 0, 0); -} - -.docblock code, .docblock-short code { - background-color: #F5F5F5; -} -pre, .rustdoc.source .example-wrap { - background-color: #F5F5F5; -} - -.sidebar, .mobile-topbar, .sidebar-menu-toggle { - background-color: #F5F5F5; -} - -/* Improve the scrollbar display on firefox */ -* { - scrollbar-color: rgba(36, 37, 39, 0.6) #e6e6e6; -} - -.sidebar { - scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; -} - .rust-logo { /* This rule exists to force other themes to explicitly style the logo. * Rustdoc has a custom linter for this purpose. */ } -/* Improve the scrollbar display on webkit-based browsers */ -::-webkit-scrollbar-track { - background-color: #ecebeb; -} -::-webkit-scrollbar-thumb { - background-color: rgba(36, 37, 39, 0.6); -} -.sidebar::-webkit-scrollbar-track { - background-color: #dcdcdc; -} -.sidebar::-webkit-scrollbar-thumb { - background-color: rgba(36, 37, 39, 0.6); -} - .sidebar .current, .sidebar a:hover { background-color: #fff; } -.source .sidebar { - background-color: #f1f1f1; -} - .line-numbers span { color: #c67e2d; } .line-numbers .line-highlighted { background-color: #FDFFD3 !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { - border-bottom-color: #ddd; -} - .docblock table td, .docblock table th { border-color: #ddd; } -.content .method .where, -.content .fn .where, -.content .where.fmt-newline { - color: #4E4C4C; -} - .search-results a:hover { background-color: #ddd; } @@ -213,30 +135,12 @@ a { color: #3873AD; } -a#toggle-all-docs, -a.anchor, -.small-section-header a, -#source-sidebar a, -pre.rust a, -.sidebar h2 a, -.sidebar h3 a, -.mobile-topbar h2 a, -.in-band a { - color: #000; -} -.search-results a { - color: initial; -} -a.test-arrow { - color: #f5f5f5; -} body.source .example-wrap pre.rust a { background: #eee; } details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before, -details.undocumented > summary::before { +details.rustdoc-toggle > summary::before { color: #999; } @@ -250,35 +154,17 @@ details.undocumented > summary::before { border-color: #66afe9; } -.module-item .stab, -.import-item .stab { - color: #000; -} - .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; } .stab.portability { background: #F3DFFF; border-color: #b07bdb; } .stab.portability > code { background: none; } -#help > div { - background: #e9e9e9; - border-color: #bfbfbf; -} - -#help span.bottom, #help span.top { - border-color: #bfbfbf; -} - .rightside, .out-of-band { color: grey; } -.result-name .primitive > i, .result-name .keyword > i { - color: black; -} - .line-numbers :target { background-color: transparent; } /* Code highlighting */ @@ -300,7 +186,8 @@ pre.rust .question-mark { } a.test-arrow { - background-color: rgb(78, 139, 202, 0.2); + color: #f5f5f5; + background-color: rgba(78, 139, 202, 0.2); } a.test-arrow:hover{ @@ -402,21 +289,9 @@ pre.ignore:hover, .information:hover + pre.ignore { } @media (max-width: 700px) { - .sidebar-menu { - background-color: #F5F5F5; - border-bottom-color: #e0e0e0; - border-right-color: #e0e0e0; - } - .sidebar-elems { - background-color: #F5F5F5; border-right-color: #000; } - - #sidebar-filler { - background-color: #F5F5F5; - border-bottom-color: #e0e0e0; - } } kbd { @@ -427,17 +302,18 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#settings-menu > a, #help-button { +#settings-menu > a, #help-button > button { border-color: #e0e0e0; background-color: #fff; } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button:hover, #help-button:focus { +#help-button > button:hover, #help-button > button:focus { border-color: #717171; } -#settings-menu #settings, #settings-menu #settings::before { +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { border-color: #DDDDDD; } @@ -471,25 +347,16 @@ kbd { color: #999; } -#sidebar-toggle { - background-color: #F5F5F5; -} -#sidebar-toggle:hover { - background-color: #E0E0E0; -} -#source-sidebar { - background-color: #F5F5F5; -} #source-sidebar > .title { border-bottom-color: #ccc; } -div.files > a:hover, div.name:hover { +#source-sidebar div.files > a:hover, details.dir-entry summary:hover, +#source-sidebar div.files > a:focus, details.dir-entry summary:focus { background-color: #E0E0E0; } -div.files > .selected { +#source-sidebar div.files > a.selected { background-color: #fff; } - .scraped-example-list .scrape-help { border-color: #555; color: #333; diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index defdc20132e67..ecbe15a59da3c 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -81,3 +81,62 @@ let ResultsTable; * }} */ let Results; + +/** + * A pair of [inputs, outputs], or 0 for null. This is stored in the search index. + * The JavaScript deserializes this into FunctionSearchType. + * + * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null` + * because `null` is four bytes while `0` is one byte. + * + * An input or output can be encoded as just a number if there is only one of them, AND + * it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had + * a function with a single output, and that output had a single generic: + * + * fn something() -> Result<usize, usize> + * + * If output was allowed to be any RawFunctionType, it would look like this + * + * [[], [50, [3, 3]]] + * + * The problem is that the above output could be interpreted as either a type with ID 50 and two + * generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second + * with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing + * in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)` + * is used instead of `(RawFunctionType|Array<RawFunctionType>)`. + * + * @typedef {( + * 0 | + * [(number|Array<RawFunctionType>)] | + * [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] + * )} + */ +let RawFunctionSearchType; + +/** + * A single function input or output type. This is either a single path ID, or a pair of + * [path ID, generics]. + * + * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null` + * because `null` is four bytes while `0` is one byte. + * + * @typedef {number | [number, Array<RawFunctionType>]} + */ +let RawFunctionType; + +/** + * @typedef {{ + * inputs: Array<FunctionType>, + * outputs: Array<FunctionType>, + * }} + */ +let FunctionSearchType; + +/** + * @typedef {{ + * name: (null|string), + * ty: (null|number), + * generics: Array<FunctionType>, + * }} + */ +let FunctionType; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index b320db9104612..2aef978a072d2 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -4,40 +4,6 @@ "use strict"; -if (!String.prototype.startsWith) { - String.prototype.startsWith = function(searchString, position) { - position = position || 0; - return this.indexOf(searchString, position) === position; - }; -} -if (!String.prototype.endsWith) { - String.prototype.endsWith = function(suffix, length) { - const l = length || this.length; - return this.indexOf(suffix, l - suffix.length) !== -1; - }; -} - -if (!DOMTokenList.prototype.add) { - DOMTokenList.prototype.add = function(className) { - if (className && !hasClass(this, className)) { - if (this.className && this.className.length > 0) { - this.className += " " + className; - } else { - this.className = className; - } - } - }; -} - -if (!DOMTokenList.prototype.remove) { - DOMTokenList.prototype.remove = function(className) { - if (className && this.className) { - this.className = (" " + this.className + " ").replace(" " + className + " ", " ") - .trim(); - } - }; -} - // Get a value from the rustdoc-vars div, which is used to convey data from // Rust to the JS. If there is no such element, return null. function getVar(name) { @@ -63,6 +29,24 @@ function showMain() { removeClass(document.getElementById(MAIN_ID), "hidden"); } +function elemIsInParent(elem, parent) { + while (elem && elem !== document.body) { + if (elem === parent) { + return true; + } + elem = elem.parentElement; + } + return false; +} + +function blurHandler(event, parentElem, hideCallback) { + if (!elemIsInParent(document.activeElement, parentElem) && + !elemIsInParent(event.relatedTarget, parentElem) + ) { + hideCallback(); + } +} + (function() { window.rootPath = getVar("root-path"); window.currentCrate = getVar("current-crate"); @@ -104,20 +88,21 @@ const MAIN_ID = "main-content"; const SETTINGS_BUTTON_ID = "settings-menu"; const ALTERNATIVE_DISPLAY_ID = "alternative-display"; const NOT_DISPLAYED_ID = "not-displayed"; +const HELP_BUTTON_ID = "help-button"; function getSettingsButton() { return document.getElementById(SETTINGS_BUTTON_ID); } +function getHelpButton() { + return document.getElementById(HELP_BUTTON_ID); +} + // Returns the current URL without any query parameter or hash. function getNakedUrl() { return window.location.href.split("?")[0].split("#")[0]; } -window.hideSettings = () => { - // Does nothing by default. -}; - /** * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode` * doesn't have a parent node. @@ -381,65 +366,27 @@ function loadCss(cssFileName) { openParentDetails(document.getElementById(id)); } - function getHelpElement(build) { - if (build) { - buildHelperPopup(); - } - return document.getElementById("help"); - } - - /** - * Show the help popup. - * - * @param {boolean} display - Whether to show or hide the popup - * @param {Event} ev - The event that triggered this call - * @param {Element} [help] - The help element if it already exists - */ - function displayHelp(display, ev, help) { - if (display) { - help = help ? help : getHelpElement(true); - if (hasClass(help, "hidden")) { - ev.preventDefault(); - removeClass(help, "hidden"); - addClass(document.body, "blur"); - } - } else { - // No need to build the help popup if we want to hide it in case it hasn't been - // built yet... - help = help ? help : getHelpElement(false); - if (help && !hasClass(help, "hidden")) { - ev.preventDefault(); - addClass(help, "hidden"); - removeClass(document.body, "blur"); - } - } - } - function handleEscape(ev) { searchState.clearInputTimeout(); - const help = getHelpElement(false); - if (help && !hasClass(help, "hidden")) { - displayHelp(false, ev, help); - } else { - switchDisplayedElement(null); - if (browserSupportsHistoryApi()) { - history.replaceState(null, window.currentCrate + " - Rust", - getNakedUrl() + window.location.hash); - } - ev.preventDefault(); + switchDisplayedElement(null); + if (browserSupportsHistoryApi()) { + history.replaceState(null, window.currentCrate + " - Rust", + getNakedUrl() + window.location.hash); } + ev.preventDefault(); searchState.defocus(); - window.hideSettings(); + window.hidePopoverMenus(); } - const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; function handleShortcut(ev) { // Don't interfere with browser shortcuts + const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { return; } - if (document.activeElement.tagName === "INPUT") { + if (document.activeElement.tagName === "INPUT" && + document.activeElement.type !== "checkbox") { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); @@ -453,7 +400,6 @@ function loadCss(cssFileName) { case "s": case "S": - displayHelp(false, ev); ev.preventDefault(); searchState.focus(); break; @@ -465,7 +411,7 @@ function loadCss(cssFileName) { break; case "?": - displayHelp(true, ev); + showHelp(); break; default: @@ -533,23 +479,20 @@ function loadCss(cssFileName) { } if (sidebar) { - const isModule = hasClass(document.body, "mod"); - if (!isModule) { - block("primitive", "primitives", "Primitive Types"); - block("mod", "modules", "Modules"); - block("macro", "macros", "Macros"); - block("struct", "structs", "Structs"); - block("enum", "enums", "Enums"); - block("union", "unions", "Unions"); - block("constant", "constants", "Constants"); - block("static", "static", "Statics"); - block("trait", "traits", "Traits"); - block("fn", "functions", "Functions"); - block("type", "types", "Type Definitions"); - block("foreigntype", "foreign-types", "Foreign Types"); - block("keyword", "keywords", "Keywords"); - block("traitalias", "trait-aliases", "Trait Aliases"); - } + block("primitive", "primitives", "Primitive Types"); + block("mod", "modules", "Modules"); + block("macro", "macros", "Macros"); + block("struct", "structs", "Structs"); + block("enum", "enums", "Enums"); + block("union", "unions", "Unions"); + block("constant", "constants", "Constants"); + block("static", "static", "Statics"); + block("trait", "traits", "Traits"); + block("fn", "functions", "Functions"); + block("type", "types", "Type Definitions"); + block("foreigntype", "foreign-types", "Foreign Types"); + block("keyword", "keywords", "Keywords"); + block("traitalias", "trait-aliases", "Trait Aliases"); } } @@ -796,9 +739,6 @@ function loadCss(cssFileName) { elem.addEventListener("click", f); } } - handleClick("help-button", ev => { - displayHelp(true, ev); - }); handleClick(MAIN_ID, () => { hideSidebar(); }); @@ -842,24 +782,16 @@ function loadCss(cssFileName) { }); } - let buildHelperPopup = () => { - const popup = document.createElement("aside"); - addClass(popup, "hidden"); - popup.id = "help"; - - popup.addEventListener("click", ev => { - if (ev.target === popup) { - // Clicked the blurred zone outside the help popup; dismiss help. - displayHelp(false, ev); - } - }); + function helpBlurHandler(event) { + blurHandler(event, getHelpButton(), window.hidePopoverMenus); + } + function buildHelpMenu() { const book_info = document.createElement("span"); book_info.className = "top"; book_info.innerHTML = "You can find more information in \ <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>."; - const container = document.createElement("div"); const shortcuts = [ ["?", "Show this help dialog"], ["S", "Focus the search field"], @@ -895,24 +827,88 @@ function loadCss(cssFileName) { addClass(div_infos, "infos"); div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos; - container.appendChild(book_info); - container.appendChild(div_shortcuts); - container.appendChild(div_infos); - const rustdoc_version = document.createElement("span"); rustdoc_version.className = "bottom"; const rustdoc_version_code = document.createElement("code"); rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version"); rustdoc_version.appendChild(rustdoc_version_code); + const container = document.createElement("div"); + container.className = "popover"; + container.style.display = "none"; + + const side_by_side = document.createElement("div"); + side_by_side.className = "side-by-side"; + side_by_side.appendChild(div_shortcuts); + side_by_side.appendChild(div_infos); + + container.appendChild(book_info); + container.appendChild(side_by_side); container.appendChild(rustdoc_version); - popup.appendChild(container); - insertAfter(popup, document.querySelector("main")); - // So that it's only built once and then it'll do nothing when called! - buildHelperPopup = () => {}; + const help_button = getHelpButton(); + help_button.appendChild(container); + + container.onblur = helpBlurHandler; + container.onclick = event => { + event.preventDefault(); + }; + help_button.onblur = helpBlurHandler; + help_button.children[0].onblur = helpBlurHandler; + + return container; + } + + /** + * Hide all the popover menus. + */ + window.hidePopoverMenus = function() { + onEachLazy(document.querySelectorAll(".search-container .popover"), elem => { + elem.style.display = "none"; + }); }; + /** + * Returns the help menu element (not the button). + * + * @param {boolean} buildNeeded - If this argument is `false`, the help menu element won't be + * built if it doesn't exist. + * + * @return {HTMLElement} + */ + function getHelpMenu(buildNeeded) { + let menu = getHelpButton().querySelector(".popover"); + if (!menu && buildNeeded) { + menu = buildHelpMenu(); + } + return menu; + } + + /** + * Show the help popup menu. + */ + function showHelp() { + const menu = getHelpMenu(true); + if (menu.style.display === "none") { + window.hidePopoverMenus(); + menu.style.display = ""; + } + } + + document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => { + const target = event.target; + if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) { + return; + } + const menu = getHelpMenu(true); + const shouldShowHelp = menu.style.display === "none"; + if (shouldShowHelp) { + showHelp(); + } else { + window.hidePopoverMenus(); + } + }); + setMobileTopbar(); addSidebarItems(); addSidebarCrates(); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index cb1609d498340..75c7bd45a2949 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -114,10 +114,6 @@ function levenshtein(s1, s2) { function initSearch(rawSearchIndex) { const MAX_LEV_DISTANCE = 3; const MAX_RESULTS = 200; - const GENERICS_DATA = 2; - const NAME = 0; - const INPUTS_DATA = 0; - const OUTPUT_DATA = 1; const NO_TYPE_FILTER = -1; /** * @type {Array<Row>} @@ -895,21 +891,18 @@ function initSearch(rawSearchIndex) { * @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`. */ function checkGenerics(row, elem, defaultLev) { - if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) { - return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1; - } else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") { - if (row.length > GENERICS_DATA) { - return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev); - } + if (row.generics.length === 0) { return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1; + } else if (row.generics.length > 0 && row.generics[0].name === null) { + return checkGenerics(row.generics[0], elem, defaultLev); } // 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_DATA].length >= elem.generics.length) { + if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) { const elems = Object.create(null); - for (const entry of row[GENERICS_DATA]) { - elem_name = entry[NAME]; + for (const entry of row.generics) { + elem_name = entry.name; if (elem_name === "") { // Pure generic, needs to check into it. if (checkGenerics(entry, elem, MAX_LEV_DISTANCE + 1) !== 0) { @@ -963,7 +956,7 @@ function initSearch(rawSearchIndex) { */ function checkIfInGenerics(row, elem) { let lev = MAX_LEV_DISTANCE + 1; - for (const entry of row[GENERICS_DATA]) { + for (const entry of row.generics) { lev = Math.min(checkType(entry, elem, true), lev); if (lev === 0) { break; @@ -984,23 +977,22 @@ function initSearch(rawSearchIndex) { * no match, returns `MAX_LEV_DISTANCE + 1`. */ function checkType(row, elem, literalSearch) { - if (row[NAME].length === 0) { + if (row.name === null) { // This is a pure "generic" search, no need to run other checks. - if (row.length > GENERICS_DATA) { + if (row.generics.length > 0) { return checkIfInGenerics(row, elem); } return MAX_LEV_DISTANCE + 1; } - let lev = levenshtein(row[NAME], elem.name); + let lev = levenshtein(row.name, elem.name); if (literalSearch) { if (lev !== 0) { // The name didn't match, let's try to check if the generics do. if (elem.generics.length === 0) { - const checkGeneric = (row.length > GENERICS_DATA && - row[GENERICS_DATA].length > 0); - if (checkGeneric && row[GENERICS_DATA] - .findIndex(tmp_elem => tmp_elem[NAME] === elem.name) !== -1) { + const checkGeneric = row.generics.length > 0; + if (checkGeneric && row.generics + .findIndex(tmp_elem => tmp_elem.name === elem.name) !== -1) { return 0; } } @@ -1009,7 +1001,7 @@ function initSearch(rawSearchIndex) { return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1); } return 0; - } else if (row.length > GENERICS_DATA) { + } else if (row.generics.length > 0) { if (elem.generics.length === 0) { if (lev === 0) { return 0; @@ -1059,9 +1051,9 @@ function initSearch(rawSearchIndex) { function findArg(row, elem, typeFilter) { let lev = MAX_LEV_DISTANCE + 1; - if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) { - for (const input of row.type[INPUTS_DATA]) { - if (!typePassesFilter(typeFilter, input[1])) { + if (row && row.type && row.type.inputs && row.type.inputs.length > 0) { + for (const input of row.type.inputs) { + if (!typePassesFilter(typeFilter, input.ty)) { continue; } lev = Math.min(lev, checkType(input, elem, parsedQuery.literalSearch)); @@ -1086,13 +1078,10 @@ function initSearch(rawSearchIndex) { function checkReturned(row, elem, typeFilter) { let lev = MAX_LEV_DISTANCE + 1; - if (row && row.type && row.type.length > OUTPUT_DATA) { - let ret = row.type[OUTPUT_DATA]; - if (typeof ret[0] === "string") { - ret = [ret]; - } + if (row && row.type && row.type.output.length > 0) { + const ret = row.type.output; for (const ret_ty of ret) { - if (!typePassesFilter(typeFilter, ret_ty[1])) { + if (!typePassesFilter(typeFilter, ret_ty.ty)) { continue; } lev = Math.min(lev, checkType(ret_ty, elem, parsedQuery.literalSearch)); @@ -1836,6 +1825,97 @@ function initSearch(rawSearchIndex) { filterCrates); } + /** + * Convert a list of RawFunctionType / ID to object-based FunctionType. + * + * Crates often have lots of functions in them, and it's common to have a large number of + * functions that operate on a small set of data types, so the search index compresses them + * by encoding function parameter and return types as indexes into an array of names. + * + * Even when a general-purpose compression algorithm is used, this is still a win. I checked. + * https://github.com/rust-lang/rust/pull/98475#issue-1284395985 + * + * The format for individual function types is encoded in + * librustdoc/html/render/mod.rs: impl Serialize for RenderType + * + * @param {null|Array<RawFunctionType>} types + * @param {Array<{name: string, ty: number}>} lowercasePaths + * + * @return {Array<FunctionSearchType>} + */ + function buildItemSearchTypeAll(types, lowercasePaths) { + const PATH_INDEX_DATA = 0; + const GENERICS_DATA = 1; + return types.map(type => { + let pathIndex, generics; + if (typeof type === "number") { + pathIndex = type; + generics = []; + } else { + pathIndex = type[PATH_INDEX_DATA]; + generics = buildItemSearchTypeAll(type[GENERICS_DATA], lowercasePaths); + } + return { + // `0` is used as a sentinel because it's fewer bytes than `null` + name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + generics: generics, + }; + }); + } + + /** + * Convert from RawFunctionSearchType to FunctionSearchType. + * + * Crates often have lots of functions in them, and function signatures are sometimes complex, + * so rustdoc uses a pretty tight encoding for them. This function converts it to a simpler, + * object-based encoding so that the actual search code is more readable and easier to debug. + * + * The raw function search type format is generated using serde in + * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType + * + * @param {RawFunctionSearchType} functionSearchType + * @param {Array<{name: string, ty: number}>} lowercasePaths + * + * @return {null|FunctionSearchType} + */ + function buildFunctionSearchType(functionSearchType, lowercasePaths) { + const INPUTS_DATA = 0; + const OUTPUT_DATA = 1; + // `0` is used as a sentinel because it's fewer bytes than `null` + if (functionSearchType === 0) { + return null; + } + let inputs, output; + if (typeof functionSearchType[INPUTS_DATA] === "number") { + const pathIndex = functionSearchType[INPUTS_DATA]; + inputs = [{ + name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + generics: [], + }]; + } else { + inputs = buildItemSearchTypeAll(functionSearchType[INPUTS_DATA], lowercasePaths); + } + if (functionSearchType.length > 1) { + if (typeof functionSearchType[OUTPUT_DATA] === "number") { + const pathIndex = functionSearchType[OUTPUT_DATA]; + output = [{ + name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, + generics: [], + }]; + } else { + output = buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA], lowercasePaths); + } + } else { + output = []; + } + return { + inputs, output, + }; + } + function buildIndex(rawSearchIndex) { searchIndex = []; /** @@ -1862,14 +1942,22 @@ function initSearch(rawSearchIndex) { * q[i] contains the full path of the item, or an empty string indicating * "same as q[i-1]". * - * i[i], f[i] are a mystery. + * i[i] contains an item's parent, usually a module. For compactness, + * it is a set of indexes into the `p` array. + * + * f[i] contains function signatures, or `0` if the item isn't a function. + * Functions are themselves encoded as arrays. The first item is a list of + * types representing the function's inputs, and the second list item is a list + * of types representing the function's output. Tuples are flattened. + * Types are also represented as arrays; the first item is an index into the `p` + * array, while the second is a list of types representing any generic parameters. * * `a` defines aliases with an Array of pairs: [name, offset], where `offset` * points into the n/t/d/q/i/f arrays. * * `doc` contains the description of the crate. * - * `p` is a mystery and isn't the same length as n/t/d/q/i/f. + * `p` is a list of path/type pairs. It is used for parents and function parameters. * * @type {{ * doc: string, @@ -1879,7 +1967,7 @@ function initSearch(rawSearchIndex) { * d: Array<string>, * q: Array<string>, * i: Array<Number>, - * f: Array<Array<?>>, + * f: Array<RawFunctionSearchType>, * p: Array<Object>, * }} */ @@ -1923,9 +2011,14 @@ function initSearch(rawSearchIndex) { // [Number] index to items] const aliases = crateCorpus.a; + // an array of [{name: String, ty: Number}] + const lowercasePaths = []; + // convert `rawPaths` entries into object form + // generate normalizedPaths for function search mode let len = paths.length; for (i = 0; i < len; ++i) { + lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()}); paths[i] = {ty: paths[i][0], name: paths[i][1]}; } @@ -1955,7 +2048,7 @@ function initSearch(rawSearchIndex) { path: itemPaths[i] ? itemPaths[i] : lastPath, desc: itemDescs[i], parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, - type: itemFunctionSearchTypes[i], + type: buildFunctionSearchType(itemFunctionSearchTypes[i], lowercasePaths), id: id, normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""), }; diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 41bf0ec895580..797b931afc643 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,6 +1,6 @@ // Local js definitions: /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ -/* global addClass, removeClass, onEach, onEachLazy */ +/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ /* global MAIN_ID, getVar, getSettingsButton */ "use strict"; @@ -209,6 +209,7 @@ const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`; const el = document.createElement(elementKind); el.id = "settings"; + el.className = "popover"; el.innerHTML = innerHTML; if (isSettingsPage) { @@ -226,23 +227,8 @@ settingsMenu.style.display = ""; } - function elemIsInParent(elem, parent) { - while (elem && elem !== document.body) { - if (elem === parent) { - return true; - } - elem = elem.parentElement; - } - return false; - } - - function blurHandler(event) { - const settingsButton = getSettingsButton(); - if (!elemIsInParent(document.activeElement, settingsButton) && - !elemIsInParent(event.relatedTarget, settingsButton) - ) { - window.hideSettings(); - } + function settingsBlurHandler(event) { + blurHandler(event, getSettingsButton(), window.hidePopoverMenus); } if (isSettingsPage) { @@ -254,26 +240,24 @@ // We replace the existing "onclick" callback. const settingsButton = getSettingsButton(); const settingsMenu = document.getElementById("settings"); - window.hideSettings = function() { - settingsMenu.style.display = "none"; - }; settingsButton.onclick = function(event) { if (elemIsInParent(event.target, settingsMenu)) { return; } event.preventDefault(); - if (settingsMenu.style.display !== "none") { - window.hideSettings(); - } else { + const shouldDisplaySettings = settingsMenu.style.display === "none"; + + window.hidePopoverMenus(); + if (shouldDisplaySettings) { displaySettings(); } }; - settingsButton.onblur = blurHandler; - settingsButton.querySelector("a").onblur = blurHandler; + settingsButton.onblur = settingsBlurHandler; + settingsButton.querySelector("a").onblur = settingsBlurHandler; onEachLazy(settingsMenu.querySelectorAll("input"), el => { - el.onblur = blurHandler; + el.onblur = settingsBlurHandler; }); - settingsMenu.onblur = blurHandler; + settingsMenu.onblur = settingsBlurHandler; } // We now wait a bit for the web browser to end re-computing the DOM... diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 290c29d3141a2..1e9bfa5cc8959 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -2,7 +2,7 @@ /* global sourcesIndex */ // Local js definitions: -/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */ +/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */ /* global updateLocalStorage */ "use strict"; @@ -10,35 +10,36 @@ (function() { const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value; +let oldScrollPosition = 0; + +function closeSidebarIfMobile() { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + updateLocalStorage("source-sidebar-show", "false"); + } +} function createDirEntry(elem, parent, fullPath, hasFoundFile) { - const name = document.createElement("div"); - name.className = "name"; + const dirEntry = document.createElement("details"); + const summary = document.createElement("summary"); + + dirEntry.className = "dir-entry"; fullPath += elem["name"] + "/"; - name.onclick = ev => { - if (hasClass(ev.target, "expand")) { - removeClass(ev.target, "expand"); - } else { - addClass(ev.target, "expand"); - } - }; - name.innerText = elem["name"]; + summary.innerText = elem["name"]; + dirEntry.appendChild(summary); - const children = document.createElement("div"); - children.className = "children"; const folders = document.createElement("div"); folders.className = "folders"; if (elem.dirs) { for (const dir of elem.dirs) { if (createDirEntry(dir, folders, fullPath, hasFoundFile)) { - addClass(name, "expand"); + dirEntry.open = true; hasFoundFile = true; } } } - children.appendChild(folders); + dirEntry.appendChild(folders); const files = document.createElement("div"); files.className = "files"; @@ -47,28 +48,42 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) { const file = document.createElement("a"); file.innerText = file_text; file.href = rootPath + "src/" + fullPath + file_text + ".html"; + file.addEventListener("click", closeSidebarIfMobile); const w = window.location.href.split("#")[0]; if (!hasFoundFile && w === file.href) { file.className = "selected"; - addClass(name, "expand"); + dirEntry.open = true; hasFoundFile = true; } files.appendChild(file); } } - children.appendChild(files); - parent.appendChild(name); - parent.appendChild(children); + dirEntry.appendChild(files); + parent.appendChild(dirEntry); return hasFoundFile; } function toggleSidebar() { - const child = this.children[0]; + const child = this.parentNode.children[0]; if (child.innerText === ">") { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + // This is to keep the scroll position on mobile. + oldScrollPosition = window.scrollY; + document.body.style.position = "fixed"; + document.body.style.top = `-${oldScrollPosition}px`; + } addClass(document.documentElement, "source-sidebar-expanded"); child.innerText = "<"; updateLocalStorage("source-sidebar-show", "true"); } else { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + // This is to keep the scroll position on mobile. + document.body.style.position = ""; + document.body.style.top = ""; + // The scroll position is lost when resetting the style, hence why we store it in + // `oldScroll`. + window.scrollTo(0, oldScrollPosition); + } removeClass(document.documentElement, "source-sidebar-expanded"); child.innerText = ">"; updateLocalStorage("source-sidebar-show", "false"); @@ -78,15 +93,15 @@ function toggleSidebar() { function createSidebarToggle() { const sidebarToggle = document.createElement("div"); sidebarToggle.id = "sidebar-toggle"; - sidebarToggle.onclick = toggleSidebar; - const inner = document.createElement("div"); + const inner = document.createElement("button"); if (getCurrentValue("source-sidebar-show") === "true") { inner.innerText = "<"; } else { inner.innerText = ">"; } + inner.onclick = toggleSidebar; sidebarToggle.appendChild(inner); return sidebarToggle; diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 1c4c88344888c..0c5389d45e5b7 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -9,6 +9,11 @@ const darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); window.mainTheme = document.getElementById("mainThemeStyle"); +// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +// If you update this line, then you also need to update the two media queries with the same +// warning in rustdoc.css +window.RUSTDOC_MOBILE_BREAKPOINT = 701; + const settingsDataset = (function() { const settingsElement = document.getElementById("default-settings"); if (settingsElement === null) { diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index c4999e2c74fce..9a551b68279d6 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -39,7 +39,7 @@ {%- else if page.css_class == "source" -%} <script defer src="{{static_root_path|safe}}source-script{{page.resource_suffix}}.js"></script> {#- -#} <script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {#- -#} - {%- else -%} + {%- else if !page.css_class.contains("mod") -%} <script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {#- -#} {%- endif -%} <script defer src="{{static_root_path|safe}}main{{page.resource_suffix}}.js"></script> {#- -#} @@ -119,7 +119,9 @@ <h2 class="location"></h2> spellcheck="false" {# -#} placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} type="search"> {#- -#} - <button type="button" id="help-button" title="help">?</button> {#- -#} + <div id="help-button" title="help" tabindex="-1"> {#- -#} + <button type="button">?</button> {#- -#} + </div> {#- -#} <div id="settings-menu" tabindex="-1"> <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#} <img width="22" height="22" alt="Change settings" {# -#} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c627dcc30d667..2598b9b0b28c2 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -43,7 +43,16 @@ impl JsonRenderer<'_> { let span = item.span(self.tcx); let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item; let inner = match *item.kind { - clean::StrippedItem(_) | clean::KeywordItem(_) => return None, + clean::KeywordItem(_) => return None, + clean::StrippedItem(ref inner) => { + match &**inner { + // We document non-empty stripped modules as with `Module::is_stripped` set to + // `true`, to prevent contained items from being orphaned for downstream users, + // as JSON does no inlining. + clean::ModuleItem(m) if !m.items.is_empty() => from_clean_item(item, self.tcx), + _ => return None, + } + } _ => from_clean_item(item, self.tcx), }; Some(Item { @@ -220,7 +229,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { let header = item.fn_header(tcx); match *item.kind { - ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx) }), + ModuleItem(m) => { + ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx), is_stripped: false }) + } ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)), StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)), UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)), @@ -252,10 +263,24 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), default: None, }, - // FIXME: do not map to Typedef but to a custom variant - AssocTypeItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)), - // `convert_item` early returns `None` for striped items and keywords. - StrippedItem(_) | KeywordItem(_) => unreachable!(), + AssocTypeItem(t, b) => ItemEnum::AssocType { + generics: t.generics.into_tcx(tcx), + bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), + default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), + }, + // `convert_item` early returns `None` for stripped items and keywords. + KeywordItem(_) => unreachable!(), + StrippedItem(inner) => { + match *inner { + ModuleItem(m) => ItemEnum::Module(Module { + is_crate, + items: ids(m.items, tcx), + is_stripped: true, + }), + // `convert_item` early returns `None` for stripped items we're not including + _ => unreachable!(), + } + } ExternCrateItem { ref src } => ItemEnum::ExternCrate { name: name.as_ref().unwrap().to_string(), rename: src.map(|x| x.to_string()), @@ -621,7 +646,7 @@ impl FromWithTcx<clean::VariantStruct> for Struct { let clean::VariantStruct { struct_type, fields } = struct_; Struct { struct_type: from_ctor_kind(struct_type), - generics: Default::default(), + generics: Generics { params: vec![], where_predicates: vec![] }, fields_stripped, fields: ids(fields, tcx), impls: Vec::new(), @@ -663,7 +688,12 @@ impl FromWithTcx<clean::Import> for Import { }, Glob => Import { source: import.source.path.whole_name(), - name: import.source.path.last().to_string(), + name: import + .source + .path + .last_opt() + .unwrap_or_else(|| Symbol::intern("*")) + .to_string(), id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)), glob: true, }, @@ -753,7 +783,6 @@ impl FromWithTcx<ItemType> for ItemKind { TraitAlias => ItemKind::TraitAlias, ProcAttribute => ItemKind::ProcAttribute, ProcDerive => ItemKind::ProcDerive, - Generic => unreachable!(), } } } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index c7251b5115287..6364d00d0624e 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -21,6 +21,7 @@ use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; use crate::clean::types::{ExternalCrate, ExternalLocation}; +use crate::clean::ItemKind; use crate::config::RenderOptions; use crate::docfs::PathError; use crate::error::Error; @@ -175,6 +176,14 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { /// the hashmap because certain items (traits and types) need to have their mappings for trait /// implementations filled out before they're inserted. fn item(&mut self, item: clean::Item) -> Result<(), Error> { + trace!("rendering {} {:?}", item.type_(), item.name); + + // Flatten items that recursively store other items. We include orphaned items from + // stripped modules and etc that are otherwise reachable. + if let ItemKind::StrippedItem(inner) = &*item.kind { + inner.inner_items().for_each(|i| self.item(i.clone()).unwrap()); + } + // Flatten items that recursively store other items item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 54b851660416a..7429f2b6ab148 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,9 +9,8 @@ #![feature(control_flow_enum)] #![feature(box_syntax)] #![feature(drain_filter)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] -#![cfg_attr(bootstrap, feature(nll))] #![feature(test)] #![feature(never_type)] #![feature(once_cell)] @@ -76,7 +75,7 @@ use std::env::{self, VarError}; use std::io; use std::process; -use rustc_driver::{abort_on_err, describe_lints}; +use rustc_driver::abort_on_err; use rustc_errors::ErrorGuaranteed; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; @@ -367,7 +366,7 @@ fn opts() -> Vec<RustcOptGroup> { ) }), unstable("Z", |o| { - o.optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG") + o.optmulti("Z", "", "unstable / perma-unstable options (only on nightly build)", "FLAG") }), stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")), unstable("playground-url", |o| { @@ -463,6 +462,14 @@ fn opts() -> Vec<RustcOptGroup> { "human|json|short", ) }), + unstable("diagnostic-width", |o| { + o.optopt( + "", + "diagnostic-width", + "Provide width of the output for truncated error messages", + "WIDTH", + ) + }), stable("json", |o| { o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG") }), @@ -686,7 +693,7 @@ fn main_args(at_args: &[String]) -> MainResult { // Note that we discard any distinction between different non-zero exit // codes from `from_matches` here. - let options = match config::Options::from_matches(&matches) { + let options = match config::Options::from_matches(&matches, args) { Ok(opts) => opts, Err(code) => { return if code == 0 { @@ -734,7 +741,12 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( } fn main_options(options: config::Options) -> MainResult { - let diag = core::new_handler(options.error_format, None, &options.debugging_opts); + let diag = core::new_handler( + options.error_format, + None, + options.diagnostic_width, + &options.unstable_opts, + ); match (options.should_test, options.markdown_input()) { (true, true) => return wrap_return(&diag, markdown::test(options)), @@ -771,15 +783,24 @@ fn main_options(options: config::Options) -> MainResult { let config = core::create_config(options); interface::create_compiler_and_run(config, |compiler| { - compiler.enter(|queries| { - let sess = compiler.session(); + let sess = compiler.session(); - if sess.opts.describe_lints { - let (_, lint_store) = &*queries.register_plugins()?.peek(); - describe_lints(sess, lint_store, true); - return Ok(()); - } + if sess.opts.describe_lints { + let mut lint_store = rustc_lint::new_lint_store( + sess.opts.unstable_opts.no_interleave_lints, + sess.unstable_options(), + ); + let registered_lints = if let Some(register_lints) = compiler.register_lints() { + register_lints(sess, &mut lint_store); + true + } else { + false + }; + rustc_driver::describe_lints(sess, &lint_store, registered_lints); + return Ok(()); + } + compiler.enter(|queries| { // We need to hold on to the complete resolver, so we cause everything to be // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index e3b349af661a1..0172ef5700b62 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,7 +1,8 @@ //! Validates syntax inside Rust code blocks (\`\`\`rust). use rustc_data_structures::sync::{Lock, Lrc}; -use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler, LazyFallbackBundle}; -use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_errors::{ + emitter::Emitter, Applicability, Diagnostic, Handler, LazyFallbackBundle, LintDiagnosticBuilder, +}; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; @@ -52,7 +53,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { None, None, ); - let expn_id = LocalExpnId::fresh(expn_data, self.cx.tcx.create_stable_hashing_context()); + let expn_id = + self.cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx)); let span = DUMMY_SP.fresh_expansion(expn_id); let is_empty = rustc_driver::catch_fatal_errors(|| { diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 6c94912bc5368..9ba841a31cf95 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -24,6 +24,7 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> retained: &mut retained, access_levels: &cx.cache.access_levels, update_retained: true, + is_json_output: cx.output_format.is_json() && !cx.show_coverage, }; krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 0fd124e615415..5f2f50e712b53 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::privacy::AccessLevels; use std::mem; -use crate::clean::{self, Item, ItemIdSet}; +use crate::clean::{self, Item, ItemId, ItemIdSet}; use crate::fold::{strip_item, DocFolder}; use crate::formats::cache::Cache; @@ -11,6 +11,21 @@ pub(crate) struct Stripper<'a> { pub(crate) retained: &'a mut ItemIdSet, pub(crate) access_levels: &'a AccessLevels<DefId>, pub(crate) update_retained: bool, + pub(crate) is_json_output: bool, +} + +impl<'a> Stripper<'a> { + // We need to handle this differently for the JSON output because some non exported items could + // be used in public API. And so, we need these items as well. `is_exported` only checks if they + // are in the public API, which is not enough. + #[inline] + fn is_item_reachable(&self, item_id: ItemId) -> bool { + if self.is_json_output { + self.access_levels.is_reachable(item_id.expect_def_id()) + } else { + self.access_levels.is_exported(item_id.expect_def_id()) + } + } } impl<'a> DocFolder for Stripper<'a> { @@ -45,9 +60,8 @@ impl<'a> DocFolder for Stripper<'a> { | clean::TraitAliasItem(..) | clean::MacroItem(..) | clean::ForeignTypeItem => { - if i.item_id.is_local() - && !self.access_levels.is_exported(i.item_id.expect_def_id()) - { + let item_id = i.item_id; + if item_id.is_local() && !self.is_item_reachable(item_id) { debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); return None; } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index f6c599297fcd6..c0fe8b49cfd1b 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -303,7 +303,7 @@ pub(crate) fn run( // Run call-finder on all items let mut calls = FxHashMap::default(); let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates }; - tcx.hir().deep_visit_all_item_likes(&mut finder); + tcx.hir().visit_all_item_likes_in_crate(&mut finder); // Sort call locations within a given file in document order for fn_calls in calls.values_mut() { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ac934f6925d0b..ca7a20bf3688a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -190,6 +190,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ) -> bool { debug!("maybe_inline_local res: {:?}", res); + if self.cx.output_format.is_json() { + return false; + } + let tcx = self.cx.tcx; let Some(res_did) = res.opt_def_id() else { return false; diff --git a/src/llvm-project b/src/llvm-project index c9e2e89ed3aa5..8b6b5014fdad3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit c9e2e89ed3aa5a3be77143aa0c86906b4138374a +Subproject commit 8b6b5014fdad3a750f7242a6bfdcad83619498d4 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index eb2c8e5bae1c4..761e94c7ebbc4 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,12 +9,12 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 15; +pub const FORMAT_VERSION: u32 = 16; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow /// tools to find or link to them. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Crate { /// The id of the root [`Module`] item of the local crate. pub root: Id, @@ -34,7 +34,7 @@ pub struct Crate { pub format_version: u32, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ExternalCrate { pub name: String, pub html_root_url: Option<String>, @@ -44,7 +44,7 @@ pub struct ExternalCrate { /// information. This struct should contain enough to generate a link/reference to the item in /// question, or can be used by a tool that takes the json output of multiple crates to find /// the actual item definition with all the relevant info. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ItemSummary { /// Can be used to look up the name and html_root_url of the crate this item came from in the /// `external_crates` map. @@ -56,7 +56,7 @@ pub struct ItemSummary { pub kind: ItemKind, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Item { /// The unique identifier of this item. Can be used to find this item in various mappings. pub id: Id, @@ -83,7 +83,7 @@ pub struct Item { pub inner: ItemEnum, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { /// The path to the source file for this span relative to the path `rustdoc` was invoked with. pub filename: PathBuf, @@ -93,13 +93,13 @@ pub struct Span { pub end: (usize, usize), } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Deprecation { pub since: Option<String>, pub note: Option<String>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Visibility { Public, @@ -115,7 +115,7 @@ pub enum Visibility { }, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GenericArgs { /// <'a, 32, B: Copy, C = u32> @@ -124,7 +124,7 @@ pub enum GenericArgs { Parenthesized { inputs: Vec<Type>, output: Option<Type> }, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GenericArg { Lifetime(String), @@ -133,7 +133,7 @@ pub enum GenericArg { Infer, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Constant { #[serde(rename = "type")] pub type_: Type, @@ -142,14 +142,14 @@ pub struct Constant { pub is_literal: bool, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TypeBinding { pub name: String, pub args: GenericArgs, pub binding: TypeBindingKind, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum TypeBindingKind { Equality(Term), @@ -159,7 +159,7 @@ pub enum TypeBindingKind { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Id(pub String); -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ItemKind { Module, @@ -189,7 +189,7 @@ pub enum ItemKind { Keyword, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(tag = "kind", content = "inner", rename_all = "snake_case")] pub enum ItemEnum { Module(Module), @@ -241,13 +241,16 @@ pub enum ItemEnum { }, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Module { pub is_crate: bool, pub items: Vec<Id>, + /// If `true`, this module is not part of the public API, but it contains + /// items that are re-exported as public API. + pub is_stripped: bool, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Union { pub generics: Generics, pub fields_stripped: bool, @@ -255,7 +258,7 @@ pub struct Union { pub impls: Vec<Id>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Struct { pub struct_type: StructType, pub generics: Generics, @@ -264,7 +267,7 @@ pub struct Struct { pub impls: Vec<Id>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Enum { pub generics: Generics, pub variants_stripped: bool, @@ -272,7 +275,7 @@ pub struct Enum { pub impls: Vec<Id>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] #[serde(tag = "variant_kind", content = "variant_inner")] pub enum Variant { @@ -281,7 +284,7 @@ pub enum Variant { Struct(Vec<Id>), } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum StructType { Plain, @@ -289,7 +292,7 @@ pub enum StructType { Unit, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Header { #[serde(rename = "const")] pub const_: bool, @@ -300,7 +303,7 @@ pub struct Header { pub abi: Abi, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Abi { // We only have a concrete listing here for stable ABI's because their are so many // See rustc_ast_passes::feature_gate::PostExpansionVisitor::check_abi for the list @@ -316,14 +319,14 @@ pub enum Abi { Other(String), } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Function { pub decl: FnDecl, pub generics: Generics, pub header: Header, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Method { pub decl: FnDecl, pub generics: Generics, @@ -331,19 +334,19 @@ pub struct Method { pub has_body: bool, } -#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Generics { pub params: Vec<GenericParamDef>, pub where_predicates: Vec<WherePredicate>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct GenericParamDef { pub name: String, pub kind: GenericParamDefKind, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GenericParamDefKind { Lifetime { @@ -384,7 +387,7 @@ pub enum GenericParamDefKind { }, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum WherePredicate { BoundPredicate { @@ -410,7 +413,7 @@ pub enum WherePredicate { }, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GenericBound { TraitBound { @@ -429,7 +432,7 @@ pub enum GenericBound { Outlives(String), } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum TraitBoundModifier { None, @@ -437,14 +440,14 @@ pub enum TraitBoundModifier { MaybeConst, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Term { Type(Type), Constant(Constant), } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] #[serde(tag = "kind", content = "inner")] pub enum Type { @@ -498,7 +501,7 @@ pub enum Type { }, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct FunctionPointer { pub decl: FnDecl, /// Used for Higher-Rank Trait Bounds (HRTBs) @@ -512,14 +515,14 @@ pub struct FunctionPointer { pub header: Header, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct FnDecl { pub inputs: Vec<(String, Type)>, pub output: Option<Type>, pub c_variadic: bool, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Trait { pub is_auto: bool, pub is_unsafe: bool, @@ -529,13 +532,13 @@ pub struct Trait { pub implementations: Vec<Id>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TraitAlias { pub generics: Generics, pub params: Vec<GenericBound>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Impl { pub is_unsafe: bool, pub generics: Generics, @@ -550,7 +553,7 @@ pub struct Impl { pub blanket_impl: Option<Type>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct Import { /// The full path being imported. @@ -564,37 +567,37 @@ pub struct Import { pub glob: bool, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ProcMacro { pub kind: MacroKind, pub helpers: Vec<String>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum MacroKind { /// A bang macro `foo!()`. Bang, /// An attribute macro `#[foo]`. Attr, - /// A derive macro `#[derive(Foo)]` + /// A derive macro `#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]` Derive, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Typedef { #[serde(rename = "type")] pub type_: Type, pub generics: Generics, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct OpaqueTy { pub bounds: Vec<GenericBound>, pub generics: Generics, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Static { #[serde(rename = "type")] pub type_: Type, diff --git a/src/stage0.json b/src/stage0.json index b6b502f4cf0cb..ab8a79e2af595 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -3,7 +3,8 @@ "dist_server": "https://static.rust-lang.org", "artifacts_server": "https://ci-artifacts.rust-lang.org/rustc-builds", "artifacts_with_llvm_assertions_server": "https://ci-artifacts.rust-lang.org/rustc-builds-alt", - "git_merge_commit_email": "bors@rust-lang.org" + "git_merge_commit_email": "bors@rust-lang.org", + "nightly_branch": "master" }, "__comments": [ "The configuration above this comment is editable, and can be changed", @@ -16,349 +17,349 @@ "tool is executed." ], "compiler": { - "date": "2022-05-20", + "date": "2022-06-29", "version": "beta" }, "rustfmt": { - "date": "2022-05-20", + "date": "2022-06-29", "version": "nightly" }, "checksums_sha256": { - "dist/2022-05-20/cargo-beta-aarch64-apple-darwin.tar.gz": "a07568445804e70f92f8b022a7397d44ac1a4ffc10633715a6ec5d48c27ea45a", - "dist/2022-05-20/cargo-beta-aarch64-apple-darwin.tar.xz": "574cb9ee69d5132317b159fa15a0651207361c1673d4c41b839bfd0f5c905b4e", - "dist/2022-05-20/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "68e566b8d4d022b4f88771d7784e092e7c78b0e2198ad901048b5831b5a1a5d4", - "dist/2022-05-20/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "f2808f120588bdf97fe5551150eaef2658967fef3e5e5ae3c531156a7312e883", - "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "92f31b6ccf0953a07c71e43b898273ad2e304afe840e4b03769122e4a6758553", - "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "6da85884371a794de85953b48d03549badb86684e2008491064ce120afab31ad", - "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "34c9ead4dcc520424ba281ec99466b921970f64320dd051ea73a09cd39f012bf", - "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "ab59385f4c61976f8f2fb31b6463b007eeaa0a71ca8dbbe884e33de4a0143c9d", - "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "68fc1f164b9f7a5c1f44d62e37c8c71a6518eff70d3397333c2fb268960ddc45", - "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "159e5e293afa533bb0259157fb2e32145d8c87921c253e45aad64c27a765df3a", - "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "aa05252a10605158ae9baca676e9ca755fb6d042d4db9121d3e933c610fe8afa", - "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6d090a90bf9c96a3955813ccdd956bf1ef1ee5c1431090f3ca4002f63703ab5", - "dist/2022-05-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "52bd65f5d845a4ca51b055e1e0e340b07a82aa7269730fef27d1c151bb0a25cd", - "dist/2022-05-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c1f96a5d59c3c93be54d82e0b2082651347e53e10ef664332f74bd6f8189849c", - "dist/2022-05-20/cargo-beta-i686-pc-windows-gnu.tar.gz": "2ce5513fb746305d61ea301301e93f4879b3cf794298ac77aec0e3eb8dea072d", - "dist/2022-05-20/cargo-beta-i686-pc-windows-gnu.tar.xz": "64a800315d0e0555c1c9fb24312c9f6375f4a3ac02b975ed413e764d238c4698", - "dist/2022-05-20/cargo-beta-i686-pc-windows-msvc.tar.gz": "1c3464b48509b0e5dee428ecb3ea27c6ec463cc0148f1d04d7d2778b0d654295", - "dist/2022-05-20/cargo-beta-i686-pc-windows-msvc.tar.xz": "89f1072af529ea55884882c11f15f8109a3790407903c6f8026b27b21d2fe0fb", - "dist/2022-05-20/cargo-beta-i686-unknown-linux-gnu.tar.gz": "57f76852b21ff37e98f441f8b7f81bb8ced7dbc310df0f03a19c907220dd6bfc", - "dist/2022-05-20/cargo-beta-i686-unknown-linux-gnu.tar.xz": "2b8885f946f9dce27098318b7c5b9095c6e62a109614355fb176c33a6cd6451f", - "dist/2022-05-20/cargo-beta-mips-unknown-linux-gnu.tar.gz": "8b39dd25f1d3a26ec6f8fc1af32f848a0e71ed408f6f2a3f6489eead634f44d9", - "dist/2022-05-20/cargo-beta-mips-unknown-linux-gnu.tar.xz": "36c47221f6c80a6e8ff3c1fb8310decfe4a8a6a247d9ad4eceb61f82cc82fdf4", - "dist/2022-05-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "eac280aae12b8825bd6dc39a674e27cc6b46f830ef3fc6887b1afcc6b75728eb", - "dist/2022-05-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "80577e2157820a70107c55102a251a08c94f3fef3841262f55f85d276ec3bac5", - "dist/2022-05-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "4c29ad8defc9b59f401da078452f9f9a7c0beb75f5edf1b91f4ac4270c707d3a", - "dist/2022-05-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "78831636bf6e2d95d7172dfa3e811ad09c363b4178f2359fc597f8470e0981d5", - "dist/2022-05-20/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "aaf75a7ea07f00888d394d69a6d438aa5c18f8e3afd93c35fd0323ac01c14064", - "dist/2022-05-20/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "026535dae96b5aed3e435d1b4d6297aeb8430587d90c074b15215a91e59a719d", - "dist/2022-05-20/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "a3c7d6bfb93f9d15d1a5bd183c985ae939c6f39ce060e177cefbe4fd7e66c48c", - "dist/2022-05-20/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "a060b3581966433d2d874e75e4f94a180a8296b23401dd41d60fd8d633f96910", - "dist/2022-05-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "77dc67bc9663de62e26752e2658468d859546f3b3dff4f33c2f2efec18a48a13", - "dist/2022-05-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "cd44e2a0a68f83f9f714f6c7142a20e244b19c2a15b136cb58d71578393bcfab", - "dist/2022-05-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0e296167172d82604e9dd36e3369662086903edf07ca4b9fd307d89b1051c8c3", - "dist/2022-05-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "28577c0e0dc0a9aae045bd834f3f5f9e4e9b3828528b1d702310baba8a8f77d6", - "dist/2022-05-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "83e3f41b7b32b77343bdc3776cd372d730eb20c382b73df84b3a427f24673814", - "dist/2022-05-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1ee99bae6c41bbcd461c26d117424f338e55dd020dbdc9481c76b407593740b4", - "dist/2022-05-20/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "529e3f38f37505ba406c3a77cbf0745dddbc87fc1296889e724194c56f5d7064", - "dist/2022-05-20/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "304b8e4c493d9429bb8723a7e002a04405d2a67087cfd601f140827b8069bd4c", - "dist/2022-05-20/cargo-beta-x86_64-apple-darwin.tar.gz": "93583a3eb5f77ea810e5938bf5c172279122d4ddedab116da507256444d0df7c", - "dist/2022-05-20/cargo-beta-x86_64-apple-darwin.tar.xz": "98e75e460994b723c31a0efc7467b0ff59d57e08692ef472d95f66b5fbd57ac7", - "dist/2022-05-20/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "652e67a93015f18b66b9cf938c1d8465498024d5c9e2f1f00eaac45500e0c1ff", - "dist/2022-05-20/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "84d3d0a3bd0c8f7f68796cac7fa27aa7054fb47fee5199d1fd3d1dd62d80fe99", - "dist/2022-05-20/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "9316dec3a49621107945f62688cea261b85ea85bce77368a44d1e69e1afe7b1b", - "dist/2022-05-20/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "8abaf2a07bbeee46421bb2a261507cda1e4c50384b0cd1008754ae34bb2b89cc", - "dist/2022-05-20/cargo-beta-x86_64-unknown-freebsd.tar.gz": "17c47c467fa31e1807f76ade9e7b9eee991808b713dcd5f27f38cd11cd24fb7e", - "dist/2022-05-20/cargo-beta-x86_64-unknown-freebsd.tar.xz": "00ca9259f5f881427e1284f60b81a0b0b9dffd6f6b63428995ac2eb8d16eeac7", - "dist/2022-05-20/cargo-beta-x86_64-unknown-illumos.tar.gz": "c83811cb7bd17e612aa74218b260d4090a4ab375b3dffd6109b4544a2f0894d0", - "dist/2022-05-20/cargo-beta-x86_64-unknown-illumos.tar.xz": "c8b8ba1cd11ee76a909540132f44b9969273287231e6014eaf71e9b72bf6931a", - "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "77decd4386bf91bf39e9f3608d6ded89c88dbb009d685913d2e7f4ebc9d6d64c", - "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "6268bfcf05e9dfb5e0d24490e4150908a233536e5c76edc3506fa174c84482ea", - "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "68d689586123f3f26fac77436c8f760e39afdc099a6eaf3ab8e3e000eb5db195", - "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "dc2d76e52bf422bcc7e65b632252970659cb416af3f7f8e0f060d8e93d94ddc6", - "dist/2022-05-20/cargo-beta-x86_64-unknown-netbsd.tar.gz": "98389a862cef3f4b0cfe1e26dac8c125be4b138441dec3aa72e1ad2215c0920a", - "dist/2022-05-20/cargo-beta-x86_64-unknown-netbsd.tar.xz": "7fe62803ee7ad464d26ad33ffe1c4babce4dd129392c9b64ddbfc58df07791a6", - "dist/2022-05-20/rust-std-beta-aarch64-apple-darwin.tar.gz": "d45607fb802929f9b61a83348141f18ec50af949bb474d22c08431e2628a90e4", - "dist/2022-05-20/rust-std-beta-aarch64-apple-darwin.tar.xz": "978bab21c453918e00cd7a61741696eb34e7099da4a69c03ad9badabba62b9b1", - "dist/2022-05-20/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "df3e94d9f805a6424bde33d3a56c8ff849c1f697f7df2ff041718e0ef3b89721", - "dist/2022-05-20/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "60fa331aba8e90db42be0540c2f274355a662dab6d184484c5be1797eb56f6d2", - "dist/2022-05-20/rust-std-beta-aarch64-apple-ios.tar.gz": "3dabf5b1046221d9d3d933bab7c5e10b001173c0388a51324631420aa0ac7d29", - "dist/2022-05-20/rust-std-beta-aarch64-apple-ios.tar.xz": "d09cab1c57cc755c01d844da79a1579410e55bfcade5fbc5ecd74c5356278828", - "dist/2022-05-20/rust-std-beta-aarch64-fuchsia.tar.gz": "94f7de28d908e919ded94e3789cd2da7e13f86ec2c141134260b531627956fed", - "dist/2022-05-20/rust-std-beta-aarch64-fuchsia.tar.xz": "789019d7dcf82403fb17e3c833f708547ec6aec51e054b9cebf783a4a0dbba02", - "dist/2022-05-20/rust-std-beta-aarch64-linux-android.tar.gz": "f8d70b9f15b1177796d0b2f7fb3273e154f70601b638d3f28fd67058b714575e", - "dist/2022-05-20/rust-std-beta-aarch64-linux-android.tar.xz": "65b50ffc7ca059df5391d2eba3b0aad6fb14ca1ffec879e5df59cf220d2aa48b", - "dist/2022-05-20/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "04c897d04111dfa2dfcf236bbe460cf3839943ae2da2112b4a2ccdbe7f0a3f39", - "dist/2022-05-20/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "8a93c339b1bf9b861497101c9e35622fb750d6e0d909eee87d012c424e06d415", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "5664d843370fdf6d5460f8fd6deaaf6da3c019f6d11375a35952b101c0dbc0cd", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "051922c23e96812354a2a4ad46ec0a02e901f9bf1ad9ee1960aa043c2b88fb0e", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "26ee4cefcf20efc100d345d657c76d24b0cfdd404f1d20cfeca831a65565eab9", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "4e11588e86fcd7f80218cbf7d5fb3be2c54b7058f29e76b0cf26a3a72fa290a4", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1dd1f1c1aded585c6d202f4fe1a275caf96b5ce4fc7f0be620fa36a05fafc72", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "9103f4c7ff155671e5d2df6faaf4776b08fbe655f5e94928ace212b888aa6aea", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-none.tar.gz": "65a03cf02a1ca34e2235717d517dba4b80de6bfaa42434ab12e50fe81ec27cfd", - "dist/2022-05-20/rust-std-beta-aarch64-unknown-none.tar.xz": "ff0492a699428be3136c8050155bfb7960bd21d1e4b8a53cf3620365c36983a9", - "dist/2022-05-20/rust-std-beta-arm-linux-androideabi.tar.gz": "983f3505a4313fa90556ecc48b8a793d3585ca7a429a7dd837270e8161f6b34a", - "dist/2022-05-20/rust-std-beta-arm-linux-androideabi.tar.xz": "6facf6686308af39ff29c9aad192aa563652cbc697e4d7a43935ee9f965ffc8a", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "c77e94254c7236ec9127f3dda57845ce6f7162569d6d124d72ce6d41c10268e0", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "772c7569d1da63842a2f6a851f9aa0adfbd9499b3596e77e76d82ac93099adb3", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2dcdc29b939d651534664fcdb1653933a2500dc98ff59b90cd988fc12f4832c7", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "a75a25b06820990b4720a60caa9d4f4b4b5a85a34078b552c52380db4239756c", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "f75de884f9219e2cd8a233b80c1aaedea1fae5a7d7b64a899b1c067c5072005e", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "69c5795861212db53e2761319ea2d408a80aef8632d8c55748be49d648a42c85", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "2809b4223232acaaba171f3d7551ac581ae5e5e848abaf7fcc0b859f04ccb830", - "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "94d389e8bec1bd6037dc1dfcd2758aee3d831ca037827018779a4da5e07dec53", - "dist/2022-05-20/rust-std-beta-armebv7r-none-eabi.tar.gz": "589e78687bafb13eb5ae1140c21a23b26fb549671c97ecde5ba8bd1549508ae0", - "dist/2022-05-20/rust-std-beta-armebv7r-none-eabi.tar.xz": "e9a81de6ceca0c0a38135e42a0ab92ab05275b594f9c03422c613f09d754054c", - "dist/2022-05-20/rust-std-beta-armebv7r-none-eabihf.tar.gz": "5805e2f656f1d5aca95977d82dcf4d08f073e3639c965d35df8e74785c29f158", - "dist/2022-05-20/rust-std-beta-armebv7r-none-eabihf.tar.xz": "64baad7526366882ae4aa9b837c9949b8382e2affdecd5dc514aea141a755804", - "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "be7e91e7c96d2e6c7c11677f6abbc92e6efd16941a5307baaa1d16b91d527fbd", - "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "bdb77d554f7971dbc2a42ddeb6ca4104344ef00dd803e099898ff0c70c47d165", - "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fa12aaf9db48d22dd3e2dd025a1738badf92ecb0659ebbbf9a530f909ce569fa", - "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "c9eb5998f89efb8bafa247a36b9377e6df06a6e0532bc3c231893d9917840180", - "dist/2022-05-20/rust-std-beta-armv7-linux-androideabi.tar.gz": "cb0d6f97d5f688d2e027e325af383274cddd78a890363dd78234cd249f33a274", - "dist/2022-05-20/rust-std-beta-armv7-linux-androideabi.tar.xz": "82491be82ab194aa8f7138985b0f071036c717b012f45c366b01d2d176b8b700", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "2805da58cbeb8254184bf652e2bc761bd20affd083473538da90386259885901", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "d04641e9efee308dc9348ab0a10fc297e9c2e1981dd683285b4b908279e07b94", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6c1db32221e1b75495de1730e7aa4c705cea0849bb5ce8ff297dc7cbe2cb22c6", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c7acf447bbb3ed25c7d97558787496987c9df8e628629b2ddb5bf47407af6bf1", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "32446694a280adde3224466f0b0d8dfeb88cee5d480f51ef324847189526ac87", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "43c54c38c7cf200d0cf7c0c9319ef0f1a21dcd700e0c1230dcd144e15361833e", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "c036a956f0db31aa089e1da0cc9deda358bc2ec3f6cad02061ba7e44e03c426c", - "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "90eee1c9a8150542beb429f910219e9eecd1b77672b29c5319b070fa5b6595bf", - "dist/2022-05-20/rust-std-beta-armv7a-none-eabi.tar.gz": "7472b16814ce29a30af4be48c0ec2711e590999521d1a519a6f12168beddff7c", - "dist/2022-05-20/rust-std-beta-armv7a-none-eabi.tar.xz": "2d01cd24d609f3f0d4d126dc4a966b0360144ba0234776e3586bf466a8878627", - "dist/2022-05-20/rust-std-beta-armv7r-none-eabi.tar.gz": "25a2f1bf856274a899fef8579a8b6efa816333fc054fe3e05e0e5d344d35977b", - "dist/2022-05-20/rust-std-beta-armv7r-none-eabi.tar.xz": "63bf6e02d710511d0f3aba7b692d5f5f66a670ea78922310f5469bf4027b4ea6", - "dist/2022-05-20/rust-std-beta-armv7r-none-eabihf.tar.gz": "0077251287e4ba5941744ce767a13c7223488488d6351ed22edb272c7d4f0153", - "dist/2022-05-20/rust-std-beta-armv7r-none-eabihf.tar.xz": "8d516d72d1315350b977057ba16aaccfce5ceeb7a5038e12071c60bb108f0b64", - "dist/2022-05-20/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "7b722a519009706c966c4eb6174fba5e858066040cbe72f6f85241c2b5ad0fdb", - "dist/2022-05-20/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "446bf5b91e4a8cfa88b788dedb273d9f315603c6db635df35c137a860406709c", - "dist/2022-05-20/rust-std-beta-i586-pc-windows-msvc.tar.gz": "b800024142e8239741e6ae2ed2ce04221699e4c688ed57cdddad4e71acc7f70b", - "dist/2022-05-20/rust-std-beta-i586-pc-windows-msvc.tar.xz": "de369ed404dc314d13ee852330718fa0a5166a255cccc7475636d5568e39398f", - "dist/2022-05-20/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "bda798e76de2751674b02c5621d077bc0d6988d97be6943e348ad69eaedf5626", - "dist/2022-05-20/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "990e63391addba79972b5cfcc8fb3a9a5ddaa6bde69816e3f55844d1923306f8", - "dist/2022-05-20/rust-std-beta-i586-unknown-linux-musl.tar.gz": "2400768ca0b4324d1a4fff2c9333296729b62beae4ea818ab63994e8850c6a7e", - "dist/2022-05-20/rust-std-beta-i586-unknown-linux-musl.tar.xz": "6ccfc6fff1738d3622f6395205dc3665f604bf91812683cdba51f72df0a81c01", - "dist/2022-05-20/rust-std-beta-i686-linux-android.tar.gz": "4511c2edf4df83a10b5953737f5e048072b0c1419a49bddd8518a5866026c3cd", - "dist/2022-05-20/rust-std-beta-i686-linux-android.tar.xz": "d22d2cb39b861dcec63d3c0f0a46367e0c4a3dee03fae2fad8f8311ce38b72dd", - "dist/2022-05-20/rust-std-beta-i686-pc-windows-gnu.tar.gz": "df4abe458226a5812bfcc382e82d1c1432bbbf4c14501121397eb26b2f1b37d8", - "dist/2022-05-20/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4416d4704bdfa42213434f8b1272a4ca20ea461be0f15de581e2e79af8837ec4", - "dist/2022-05-20/rust-std-beta-i686-pc-windows-msvc.tar.gz": "8ff11e61449c5a4e7395f9caa803057ac630259532efb666921a279bd32e09ed", - "dist/2022-05-20/rust-std-beta-i686-pc-windows-msvc.tar.xz": "d31c0cfec27086ffb2f257b204eb6fb2d8950c73383137be5590ad39e3473d5e", - "dist/2022-05-20/rust-std-beta-i686-unknown-freebsd.tar.gz": "0461fda259436063bbb4605c6c933bf07650091e745e0e435f0033f315177a70", - "dist/2022-05-20/rust-std-beta-i686-unknown-freebsd.tar.xz": "7c781c344b2d11a46fbfa5166645b8d851d7d7d1a8552b53cea8ee0c09098a9a", - "dist/2022-05-20/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "2cb9052d6a9e5cadde06c45dc97e2fac06f6aaa92a04cf83599944d8f8eb2d63", - "dist/2022-05-20/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "3a17856fd2c95553e0cb38619dac7417d9aa09d2062ed20aa230425e41351126", - "dist/2022-05-20/rust-std-beta-i686-unknown-linux-musl.tar.gz": "cff1e6bf0f2d959d7ae18975e0f453b801eba70a9f1e28929628e57e5fbe3c98", - "dist/2022-05-20/rust-std-beta-i686-unknown-linux-musl.tar.xz": "27507f85b579e2cf6f405d45b5efd91719d4d13cfb2244b81a198b6fe1eca9a9", - "dist/2022-05-20/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "b5f0992efce6efda759f2a05c2f87218c3831d26ef1a30629bfc047be07a252a", - "dist/2022-05-20/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "125ada363a57b69def167673791877213128fac96ca07c48b812922c8032797b", - "dist/2022-05-20/rust-std-beta-mips-unknown-linux-musl.tar.gz": "d0ecdf9b14faeaaa1260bcabe76c4b0f6e7b6b81d5efb920fa7d0ff4c2ca3320", - "dist/2022-05-20/rust-std-beta-mips-unknown-linux-musl.tar.xz": "5b5b4df31260e89ad4e3f927c1999e716b6b47a6cccb9e4e9cc8728afabe8af8", - "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "03c9e0df29ac2dc87ad5f10f1e4ca8e1faca86e9db1e14dc111ec6466c18e3d9", - "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "71e3e3f092c20a782873f0ccab896c825985dd37382d431b19be104356772a1b", - "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "a3d5b7d50d3df53072de703a86e45f7d933449eaaba1da5d99ec62432746d4fe", - "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "0281d7f8325ada1b46ce077dd1466a0dc60e3ed2fdbc187d3e3d709fe1971fba", - "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6a88c79fd895450425f110346c9edea479602179d743b52870e5de63d136fe5a", - "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "57648390e7a58188cf53578733ae7e6b56171457e1f733ab53f2b33817201a90", - "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "1367e998ddfe049f0c7127076c934000aae07739af264b7a42932b216c968a79", - "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "08eea3c826005e9c0f3017c71200e25c360dc72906e14a1460692230557b40d0", - "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "1c39e3d2296a35c9ffe50cdacc804ae6c8f2cfa07b1fcb62bd054fa6b5ed8d79", - "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "0390c75c7e685ba962698a1499cdd4f4bdaa5557a3e1c18f978d9741906841b2", - "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "913baebce845df4e6f31904be1bd983a677fefdcab37b60e1dd3dd2ae8e8154c", - "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "327d3fbe131028aee1c29ea3372e0cf38a4eb8ef34d536efc7f804c6d5f40ab6", - "dist/2022-05-20/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "38800fe3874563ca61643fb3782c54e369d6731454520e1245f24daf60f6acbd", - "dist/2022-05-20/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "23a497126301502347dc35a75cef01f31fe994879b04862b571432e1549be85b", - "dist/2022-05-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "2bb6b51cbd83f3cc14e00bdc2133a14e0abe735cad30f7e1b001535784f98dd5", - "dist/2022-05-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "02894b90eaed0ae7712c3818498800a0da089969c3f9ff21d309aab6e47e857f", - "dist/2022-05-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "d889d93be28ee0b28832543691a15c2849726ec87dc3fccaea9465f7447f176f", - "dist/2022-05-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c980f3a1d45cca85fe32123dd142776d4b6684ca1625f6e1d249ac5d8ea27d6d", - "dist/2022-05-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d3e8359eb9a35ac442a613f6fd82e8d5c9d681e8af7063798227eaab3e72604d", - "dist/2022-05-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "eea426cb15d15a0eb06e9c3b0e2e96cd2626c9f50d2b185c0c99d5aebc9bd3a5", - "dist/2022-05-20/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "d0974d9b70b464ae3172c15e8fb304424b591d7f06dbbf49137a80819ae7334f", - "dist/2022-05-20/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "30bc0890da242ea54cfd498cd45c0616d3c1c812b92a149ac10881e53d976295", - "dist/2022-05-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "6c33e98b2bc61aedd5eda2a321f4e7e94709709c450fe0958197cdc82b2810ae", - "dist/2022-05-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "43cabe1ab3c37c4d62286c0e9ed34eb736c63d9fb4c36199965b10b20ca80b85", - "dist/2022-05-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "59ff30ca51024a6e1bba2171ec48af591acb03359200a0c1affe7834e02052aa", - "dist/2022-05-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "5d1ae0d7fac3f2b0e5192faddbd7c78a1a8c08faa056750625043513bc6235fe", - "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "86a083dd8ac10659b70db9fdf6d26b4d4c17a170582ae42d58d88840e75baf17", - "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "284144e4c8bb3dcfbbc67274b78db1a9bd0945bac757b99b2bcd1c365d7fb020", - "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "0f3c7ee9df5a967f1cee60a41c5f0e6e52f47c30b47f2e0b55efb0c05c0817fe", - "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "4ca5336d556f9b925731f1f39bc644f7393faeedf6abedce2ed0cd30736051d0", - "dist/2022-05-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "37e9f9dae9ef0fea6bb223d62cb4090549a8f0ea8e316729204de87e120a46f9", - "dist/2022-05-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "295bd6649e36489b14851002f082621cb5f2eaa7a1ab99dc7553413f50ff9e48", - "dist/2022-05-20/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "e0eb8ed3f1e078a2b0061f3f73add38a7a5d977d2c1545d1d1c6b7432efccbfb", - "dist/2022-05-20/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "3e119885f8d9d72e3cfeacca1c0bcd734000a61d0b3336d3010ee306650f78c9", - "dist/2022-05-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "ecd2046ead142d3629a5a0316e56dc03df3cc9e995fb1ab9e347d0dd2f563ee7", - "dist/2022-05-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "4288ee173cf81a72b4f9a45360734bdb8c880de7899cbe0c990ff3ec1cb2ec5a", - "dist/2022-05-20/rust-std-beta-sparcv9-sun-solaris.tar.gz": "4a7090a8d82f1f2c46437ad38c2659deac691c2fd179bd47ecdecdfac57a72ea", - "dist/2022-05-20/rust-std-beta-sparcv9-sun-solaris.tar.xz": "17daaaf6e17a237a8d4effc1ba09e50feeebbe21dced1f89249dc116abc141ff", - "dist/2022-05-20/rust-std-beta-thumbv6m-none-eabi.tar.gz": "7a7bf1342c8ab564ea29f7745515c0272435704ba1f9bc56875fbdb957286231", - "dist/2022-05-20/rust-std-beta-thumbv6m-none-eabi.tar.xz": "5ec32ef9e0633f78c5f4f74c7e572749c523c8e294fd0c3b012925ee871a2cff", - "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabi.tar.gz": "36ff832f4c190ceb2f5d241ca45dc3137fe0dc1c111fa70d310908e1ecfcad86", - "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabi.tar.xz": "dcbf2a0e4da89ef8fd60b9e334c3d6964e795a949cdcdbe90bf5624124979076", - "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "299b6c26d623babb5720962b5b08a7495514373646bfcfe25f32f1118a149d05", - "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "dcd19b9b8d52acaf36281d1927aea01b581c62d6575ed8913b01822cb36f73b1", - "dist/2022-05-20/rust-std-beta-thumbv7m-none-eabi.tar.gz": "0f81c759b3843994f01e00e86f0fb17f203be11d085e6e118e0032215cad0366", - "dist/2022-05-20/rust-std-beta-thumbv7m-none-eabi.tar.xz": "ef240ba96fc9c1cfc87e49d562d34e323bbd2b703ad72416189d588800993798", - "dist/2022-05-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "9e6f2fbd877f3549caf65a7bee05dc338939775b9df3e55b3261aa56ebb783be", - "dist/2022-05-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "23e81f67930983344401785226c5e52f02986b8d2cefc580cbe3a39727e8c190", - "dist/2022-05-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "1a34d653ada70fa611e159d4ceec689884ba1a5f4c44822d0175c7a7a37a7de3", - "dist/2022-05-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "eee5b5c5a686f8de92535cd291c0ecd7ec861033460ae2f2dd047025acb10f27", - "dist/2022-05-20/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "56cfde72d635c72648d6bac79a7a9dbd1621474804df82b23cd6e4b3df327f6d", - "dist/2022-05-20/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "105a3991cd8d9013b22d5bb6bd9d8bb1a95597341c042985a589390219a1cb22", - "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "0ae3c43289f939fc8d0fe365bc1bd17e3adaa05942c4e6f65e989de925bff5e5", - "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "be973d27b5a73ea40b60a8e1b281323ac557d35d0f20b69eceecd89c98b6a8a7", - "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "8630bf9e2082512441961ba0e970dcf1a2cec2b957938be3e671cabbd98fc5e3", - "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "ff33377187bdafd55ef8eae0a10255a306e7e0ad06f8326c26495169e7099a6c", - "dist/2022-05-20/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "a6b50581a4269fb83accc468f5f6fc697ecb0060852f3c1aca347465bd9631f4", - "dist/2022-05-20/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "1a9b35e8270048be5e44ec318669acff1c1348d5086f43d67d230be7089db920", - "dist/2022-05-20/rust-std-beta-wasm32-unknown-unknown.tar.gz": "bb01aef0726534fd606456e38fc999c6683555bf8fadf1a5f390491a8a288b22", - "dist/2022-05-20/rust-std-beta-wasm32-unknown-unknown.tar.xz": "36b0f7c5bd3ba18e1a32dead937fe0bb3d28c864e2aa3d4bab4bee61ea6730a8", - "dist/2022-05-20/rust-std-beta-wasm32-wasi.tar.gz": "188265a7ef61ce9c3676ff28edce226196945b681f6ad333837759a82a2a608c", - "dist/2022-05-20/rust-std-beta-wasm32-wasi.tar.xz": "5abb86cfe2be1d1b631f33b7601dd66d9a0f7aa01a37c88b3eafabf49bab84a5", - "dist/2022-05-20/rust-std-beta-x86_64-apple-darwin.tar.gz": "b605e10547a5a82375030606986f8ca69c4c03e87526a6eb4ef967ed173d36b0", - "dist/2022-05-20/rust-std-beta-x86_64-apple-darwin.tar.xz": "70274d4a46996db65c40cf2391d162fe09426b1c1aeaa988f48bdcc39740cad3", - "dist/2022-05-20/rust-std-beta-x86_64-apple-ios.tar.gz": "494b20caa398346eddd66a3df6f10601d96dac4204c7a235823e4627534111d4", - "dist/2022-05-20/rust-std-beta-x86_64-apple-ios.tar.xz": "1c62f0df4b9b7661c4dab30f501bf01956934480d0d47bc9d0be591e2c73c8be", - "dist/2022-05-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "4083489fecd16a34541670a2df9e5182fc0a15b6204d0a9af973676e691e49a6", - "dist/2022-05-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "5a65b9d25d04e7d0fbbadd188fbb013fb1034fe273e2b85cebaeb6aaebe06ec6", - "dist/2022-05-20/rust-std-beta-x86_64-fuchsia.tar.gz": "447eff000d01bff74a4da75b12317979adb07e21a6a81c35170f5d9e7dda8419", - "dist/2022-05-20/rust-std-beta-x86_64-fuchsia.tar.xz": "34e6f5225985d454d55f9c22828ab46cd560c7108e259a6aac0e9932d079c7b2", - "dist/2022-05-20/rust-std-beta-x86_64-linux-android.tar.gz": "67478f922ba588f4f0e0fcff23e254115898266bcb8868ccec8494ee680af6f5", - "dist/2022-05-20/rust-std-beta-x86_64-linux-android.tar.xz": "08c3330a0b25365e8c7404119def5ca630a370e832a0dd62c54fd2409be96650", - "dist/2022-05-20/rust-std-beta-x86_64-pc-solaris.tar.gz": "e293bed46bf31439f8a87eff36046a12c439b1f6f8c7a67030b44523999b39b2", - "dist/2022-05-20/rust-std-beta-x86_64-pc-solaris.tar.xz": "0e03e0c918cdaf94a33ad8225b483e4174085239ebe406d906a4cb95b44d227d", - "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "73d66833913d4606453b89b7f72b5b4c417c9baaa09b854c6217441b5d8893f8", - "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "6500d80a332e27d235d562dee7d48a0baf05876595d813818f46de61ef75f60a", - "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "80459e06662ca8789ec35793832b0df912b51ede0a62c46f52a3fd2a94bc6488", - "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "14a073ddedcfa34ecca58e53467ef874fbed4eb10003f3b2663f49c77890418c", - "dist/2022-05-20/rust-std-beta-x86_64-sun-solaris.tar.gz": "f3939d1e526f9cd8e1114ce9f4521c563d4e4b43f2f6889c292b2e02bba79c0b", - "dist/2022-05-20/rust-std-beta-x86_64-sun-solaris.tar.xz": "65ec686465eb4d2b3013da46cc83f1f80cddcdb70d8449d423464368c024881b", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "878f6de25e6934c91138a2257b81338a0da4a83dd8233d2ceff2e26e9bad8bad", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "ffab6364f6af477b074774a9e1915636f07b0659231c61bb7c75cbde31277986", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-illumos.tar.gz": "52b0580aa5a036526100b6032e104f1f790c1b7346494ca44f017cd8957aff07", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-illumos.tar.xz": "58da0d760adc61b63d72851ae602927ac9c71795df103a6b6342f210425eb5dc", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53e3312b8f96723319f791d54a3215d427fefaa353485bd7940e1ffd875bdeb2", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "0194620a7501c555d157b37759b1d97c35a78a5561cb3859688ceb12184e0636", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "17939ba3d5aaed0e79246378bdb2694e830b02b4c56941f7cca30400d3213d09", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "1acd94d6881951001ace4bf76c46775199097710064d3a0da03cd5979d23bcc8", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "bdcd08dc5dff810b28ca466e4984f1ef2e8f079d233d1b9933ac719b9a2e5a14", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "d7629d65c4908a7a74aedac7f7fa52c2308dcfcd6c8e541a0fa418dff3304152", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "02c2e64930f37200125415e7212577cf25dbd5c76929bc629313e856960beb68", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "2fecb5336a79c62cf1e17df7d65604c3df19b8cc9c490a2fc918dac1ab843989", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-none.tar.gz": "b37f013037673d8f405900170d3c5c94476946df6c6eaea9e3f98354e05ffb22", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-none.tar.xz": "53d4a5aaebc4a8fa39ac5157a90dc80ee168df51b70f21e01c26b20d00df94dd", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-redox.tar.gz": "d7e8ef1e4655bcfed48081cd59b78d08585b9c9141601128efb8081ec908f2f8", - "dist/2022-05-20/rust-std-beta-x86_64-unknown-redox.tar.xz": "8117ed18c3742af2c9f193458540b700d2eaeb98c7774b52942fca3a605e98f9", - "dist/2022-05-20/rustc-beta-aarch64-apple-darwin.tar.gz": "5da43198c82b323534fd7163e202daa6256dcd2ce1c6001f07f1746c43738216", - "dist/2022-05-20/rustc-beta-aarch64-apple-darwin.tar.xz": "35fe159afe40b969f948590313be24f3c626e6dfe53211dcc57ca63d930903b9", - "dist/2022-05-20/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "878aecc6259747dbdb64b62eb741ab4c77215475b5ba2ab707be772f33c65370", - "dist/2022-05-20/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "e43637e5ec68302e6d652b1296fa86b5dd0d3163298ad7db298b2185d2faebad", - "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "496ff30ba1820bbb27d62307e1e74352dfe39fdce5be1abe96370df059507131", - "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "ff679573cac7cc417ee90773e378453a41f5a67ee422957d03293e90c7ccd0b7", - "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8440a56c20b9f999e577c30c04bf57500b1faa5f4d6794cdf94682202d072f41", - "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "318569c2e30ec047f870727f849d07e21133f04ce9d9f6ef71b6db91745102db", - "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "ef226baa0d484a8a4426570f8556e50ea0d6cebe4cd8662b78cdaa6b32645712", - "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7aeb63e2390fe4043a047bf1309f9e39dcbe7745540fbdff4572b24d5e084ea8", - "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "30f65131a29bb094eba2d8d7171fa6da8159d4d8f33af6f930b605119e393563", - "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "70555b5fe9ef11d6aeda526832a187be3e37cbffe9757b2d0690f2c0673057ba", - "dist/2022-05-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "55d7031a9e47b9b782c4ab2c8c4b2c4fe98c44eab6b0c059236a1d1c8dcfd0b8", - "dist/2022-05-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cef673c540259008168a8f23bb8a6574196f4ba8b802c07f5474f6fe733667bd", - "dist/2022-05-20/rustc-beta-i686-pc-windows-gnu.tar.gz": "8598a985340414f8176728d79d6ef602fb3283668b2bc3f1e8b3933e8cb25030", - "dist/2022-05-20/rustc-beta-i686-pc-windows-gnu.tar.xz": "2df61a11a8f688a4f3bdb7298f3a7e929a2c737295414c033405e5bf55522729", - "dist/2022-05-20/rustc-beta-i686-pc-windows-msvc.tar.gz": "280894eb39a07ef35c2eb76fab8e77b25b54bbcf4a03a49e21edc528a14912a4", - "dist/2022-05-20/rustc-beta-i686-pc-windows-msvc.tar.xz": "01260ef26a28c21a76187cd84a7d1195137d3f871d51e559422dd017f8cc6920", - "dist/2022-05-20/rustc-beta-i686-unknown-linux-gnu.tar.gz": "ce35952f8a49a4f2706e8fbb62e21d5419f90058b66b057e669f69c522bfbca8", - "dist/2022-05-20/rustc-beta-i686-unknown-linux-gnu.tar.xz": "32dc234a4dacdddd80cd23c9e64d2f45b1854651493958f0789b3ea58800d9b8", - "dist/2022-05-20/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e5b1f27084d8082840fa76222e48b1a55c28209f100cf55769375e72ee5f7298", - "dist/2022-05-20/rustc-beta-mips-unknown-linux-gnu.tar.xz": "8a56067a0c6910ccc822f87b7eb0f12834d00c9840e9a937928a519093ed5041", - "dist/2022-05-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "fc51757845b46433ff6a53a2a783df1810072a456c9611c7eb24ccd97a99845c", - "dist/2022-05-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1c29e7f1519275a88a48ad2687e9368e4633f9bbc6b1467dd064000a6315163d", - "dist/2022-05-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "29cab4f76a3b2c916280eefd8a72b9b9014174b2de8cd62f18add7207f387821", - "dist/2022-05-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "eb234b6bc941757ad31f5f4ae08083846101697dd8ff2ccb6f62a728eeb0a4b1", - "dist/2022-05-20/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "107d59c38607e0b0c4853d08b5a05e1e7dfa01a1ea42eae88180b27d0cade79e", - "dist/2022-05-20/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "248a58d873bf4aa9872ebd7b1d903f84f713266abfa40c2f24b2a2125247f2b1", - "dist/2022-05-20/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "1b91a2ccae1eaf8654d5338aff78c630bed772b6960349dd54b71a769e1fb7da", - "dist/2022-05-20/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "4cd2421996965d58cd1318761301b2a5b9ae852f5518091a27eb64818f5b6982", - "dist/2022-05-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "c892a97b55f6f67803f23f1a59fe084a06f31973cb8ee244836c00210a323095", - "dist/2022-05-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "774aec0f0543255e948ce3aac921b7d1eff054aabe5478c285e08312b4fb0023", - "dist/2022-05-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "deb42e8f3e18206fc4795829e13f68be17ef7074196fe4880addce40adbb2825", - "dist/2022-05-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "502b33478bdc56ff705ef4001c59017f6a7057f370d388b42ca697aeef696b3e", - "dist/2022-05-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "4bd2e1d502b9f0b6bb1672c94c54650e63b3b28845be4a7148f6a15e062a4c95", - "dist/2022-05-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "51fd5c0841d6f9881a6f1fdc3b261a085eac64a5521546f2b18756cae4472e15", - "dist/2022-05-20/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "209fe3fbf4632517921723e67857c1697e6cb0c8b56ecd8678205909b586c156", - "dist/2022-05-20/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "27c66acc0c71d232d0c43ad15a8953b34dfadb87073727eb1b574b1debabb9f8", - "dist/2022-05-20/rustc-beta-x86_64-apple-darwin.tar.gz": "bfb46c4a6864fde3b4edf3500713d423404ef39ba8849b229e823adda5a638a0", - "dist/2022-05-20/rustc-beta-x86_64-apple-darwin.tar.xz": "bce0d4dcd41b8a4d79718238355b0fe682b83620ebaf4a134fe5b7e7c2620c32", - "dist/2022-05-20/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "6c281db4eaa67c74bd07e56efff6fe63e750aa9a5dbd92edbc86c68f69964381", - "dist/2022-05-20/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5c4f1bd38095e9c34c5357a76fa5090bf82a030fcc1b18a2935b9fabf02f9f57", - "dist/2022-05-20/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "0e4e6b6c236cf3ed4c5de5ad909f060bba6ba9fc41aa3d5bbe72d90a7a3c8976", - "dist/2022-05-20/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "a526b05166251ddc646961388e24827c05b86e7d61d8cbd0015f6a98b742f9ea", - "dist/2022-05-20/rustc-beta-x86_64-unknown-freebsd.tar.gz": "1cd1d3a1a37bca47f7a00182e5c0a08275091a8d36771504a84052c1a72dec4a", - "dist/2022-05-20/rustc-beta-x86_64-unknown-freebsd.tar.xz": "460aa68d922df97fac6d6052a8680d514fd4ce32fca7c44ae22d7c05e0c5b51f", - "dist/2022-05-20/rustc-beta-x86_64-unknown-illumos.tar.gz": "d992c3d0b088d359dafce1ce143e698b81c5bd49c9537e035ad8734fae7ba671", - "dist/2022-05-20/rustc-beta-x86_64-unknown-illumos.tar.xz": "28234a4d0417b1d7bb112775fc3827115777d288a6c40628d234f2724c94a8ba", - "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "169a34b8288c5cb9d79c225a6b890d936942ceda046823b50ffc8c0ba6dc9d1f", - "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "9a4963614650e4f3d7a24f4e89f100aeb96d8faca3ab9e912fc66d92364c50db", - "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "493ac76b6e2324a4c0ffc7136f22a6b5c651bd464b240814e4de42d2d52db737", - "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "f430f5eb951d367543f65ed9fdb7de2bca8e8f06b6f7c10c8a97a35f9787ca39", - "dist/2022-05-20/rustc-beta-x86_64-unknown-netbsd.tar.gz": "ae878bc9dc0d7788d2098cdbf5b564a624b1bc1419f8c0d574f5fc3a0cb13511", - "dist/2022-05-20/rustc-beta-x86_64-unknown-netbsd.tar.xz": "de65cd47cb84cc446121cf85af77e8f50e8e3ce82db1fc66c88686334b8541a8", - "dist/2022-05-20/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "016ff92402d8095a9a58e82dbe435fe5b8f64ff63ecdbc8b48968f10f8c94947", - "dist/2022-05-20/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "7c2c2d3a6cae8633d0013312a1dcf24e583261ff88f582760df81c298d848cb0", - "dist/2022-05-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e27dde14fd9bf882e8714628de56e9877c56d31d889c7d2ea03713cc8158a4ff", - "dist/2022-05-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "b58836984c2fd54054fe436fc49cbd7570bf6b1534ef030acf29e3cc4c70d58e", - "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "33dacee51735139ace6af54c853304ef2d9f3917eaf5c84ebb69ca3555d23c42", - "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "2ea9b4e7a0fc641b1fe54b21c415277e43df9d7a958b0c3b02f60b38a06c8ebe", - "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "829ca9581d19adbaad12a77d1e318bd5d08daefc928c6c6a48f3b5276039b518", - "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "e9a8030c2a065da4e0ba61b57747cd8dd40cd3d4bfcf8ab5873618620dcdd07c", - "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "e2e389076858a5fdf02c85d036b07c3fbdeddf1b526de8d8e72223241cf2f5c7", - "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "21df340cc4741e1b6265f67e8068e81e255fab82f1c18070b24245e52022753d", - "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "681b47f3e5cdead36f12ca8af4b996d4aa90e4ca471c604de13faa70ca22258b", - "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "e842733f877c401f55924fa1c5c608087aef9901c79664afd4bbb53e6af9e46e", - "dist/2022-05-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "7c43e97e824fcb2595b416f50cf3bfd6930f3fd066e8d27673db478ec87667d1", - "dist/2022-05-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "fa13900df7709c8258d7e2ecfd5d9d4a620af957604d2544f5114ce9333961b7", - "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "7378857f9d524eff3fa81f7724b687e7b53f686c22bc40825bb9df06e5fc2652", - "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "6c4cc08f7474e3415b78dd5f3c7554b6af7af3e9c0143cef24dd2803b19bfa24", - "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "b75b7226c3601d6e3c701ebe4e53f042754d9bf37ed933548093a2de782b4e7e", - "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "628ee041610c8f70a7e033cf5f997cee0974dfebefbd2867a4b55aad0e72ecad", - "dist/2022-05-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "62e1293032535dd706efea3ed395da3756ab2db74b1eb1aa12333f9d3cdcbe20", - "dist/2022-05-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "0b4bb25aabe8915ef3e3ef5822dea1ce55ea3f07e2196552abe058df91600722", - "dist/2022-05-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "aa80e17777a3b5eeb94bb14fd42df24dc0a7fd01d5b497c8ea904e2f8990ab20", - "dist/2022-05-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a18cd7d9bfc9b51ea3cf722a4b6da3897bbf29710bb837bce2a493601210c749", - "dist/2022-05-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "5b50d88dcede9527a133352a0af57609f5ab035e5080298bc6e4472dd8def994", - "dist/2022-05-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "5f7c9544eb83dedce2c0f34fa4492b68453a49ce69dcae6d20b23e4f5658b674", - "dist/2022-05-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "d8282c23352c4a84da032af5286e7d4dd478c721efab1a87a0c6d78d5b810cb3", - "dist/2022-05-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "8b6137beebe10ada8c152edd6d2e59c8e348b79cddd72d55704e65375bfc1363", - "dist/2022-05-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "5ee13136a127ede81125cfbf3cb5a5e01f4c628f6905964253555ba93abd7d68", - "dist/2022-05-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "44732a16066b78ff12c87d09bd4e409630c16e89f6666e4d0feb4fac7291610c", - "dist/2022-05-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "c5c4246bda76e04f9f6e0d2bd6b9d0697da91a5714b5bbcd20f005f51c2133ba", - "dist/2022-05-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "62aed94d82667d952a5199549d92e10ef3b0fa0fca50cca1e1ef8148939de7a4", - "dist/2022-05-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "5cabed546a4e47408870815df117d1679eb55498d124d74ba59ce5d3a2365856", - "dist/2022-05-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "27eadfa90c307e32b7bde08935a3d3f6710fe2c134138f8972e73d52fd42f2dc", - "dist/2022-05-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "d0b9466a62f79e00000e53dd23889ce148b157b2450b9cdcf072fa1d0ef0d9c5", - "dist/2022-05-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "b18b418cdc40a46020ed4b4bdc001d1f53d564e31b2d7163c4b8d4c2b0858cda", - "dist/2022-05-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "b1ebacd2f47471dcbb2d4503de85cb89f30182842ca985aad152ca7d58ed990f", - "dist/2022-05-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "caad69f3c84bab683907252a9c50b7d54ac61062282e3eb5c5033f2bb8611cac", - "dist/2022-05-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "afd79b45aaebafaeb4de5a8e018549e5d21f37e1aa025943103264ac011296c6", - "dist/2022-05-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a7c5e50b4423800f489386f1c049190a79a34e472aee932193f32577321d94e", - "dist/2022-05-20/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "7d85e16802a0c38ce2beac5ca01f9921e9ca1df5bc413bfc8d129143228bdda9", - "dist/2022-05-20/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "7ebb79d71ed525e6324ea7e1840fa88c76a37e8082ada2a02532aff696b2623a", - "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "823bba430cd01425c207e1ad58689b1c79143d4365dce40322c59462d658f3ab", - "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "13b92baa7393f6f2a2e6743366189a6518f2233de98a09c3d7a1f4e3159214e7", - "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "ee9407a567b12a4fa6b0c596d1a775d45d016badec8f9e73ef66ff324aba0d87", - "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "7cd8f5b0a256574c04b4a4b79e19a53899f89884c3f34b11ee6352be89ced09a", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "9a40bee5b8ef9305de4075595ccb9b698574cd8ca4d355b7474ea7009f7e924e", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "80a5d830e5e2750aa9b1c5e46cc1f97910473cca0ff20a93a5b81d5c664431d0", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "b3e45e2b6b984838dd156bc00d0d9178793d1c7a895fa016bd18f1c15fb65111", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "dfbba7787c57cf47b75033b81523de52c1be3072a1f68564e9bf5f93378d18a1", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "913000f2bd4787ebf301d7d0b80cd480d4afd362f3728c9886ef898b0286575f", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "7ebc5f8f6fccb5eab1eeffb724baf320ffebb653bce813841115b7e67144b2c1", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "6a4550b5a5dd7d91f9767954c8a7fab31e3a782d34d524823f1add8679b19a26", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "b3e9ab1bd65ca0957235f1ce946c7893a5c1ff4276193ccb1763819ae1e053b0", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "b52a56a4195e41496b9a96ea41a05f9fa27b3c47851ae3aafffbd37711a522f2", - "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "accd31a4772443dfa87121f30f501a53cf8f2be5553b1d7fcdf0405d2baf2149" + "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.gz": "8e50ef7a6fbc0e7212621e124de66d123b9c772a04cdb04b5528cb68543f89d0", + "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.xz": "f74e110c8740321406acde67c37fc3dbb47e9d98e25bf20f5ad19790b89b9b9c", + "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "14067f4013c5e112531ee4f76e7ba61149b46a67d1d8bf0256dc2ee1410f44c9", + "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "9252a221a244308228a16f5e9729755d9f09421e2e316ea82f64da1d9a8c4725", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "38c0b9186fb251a6ac15ced667d3cd719e81acc0eb7a92303c6422c92b701842", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "b328753578ecb5ca9578f9ac89107804249eb4f802ca0f07c9bdd063aab931b5", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "747d836695e7a385e6af22911966f72410abafe8b400b33690804e4290e750ee", + "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "94cb8c5e70ba4da6de86777c3c2092ab0616da9d12fbff6928e901fd6c48c099", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d3fa253a3a470d65f726dd59201c3b6e90e8d2343d3b5a1d27ba395d16ebe025", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "84f4684cb6e86e58279b768e8cc00c55da09a0ee8cdad77dfe4153748eaa3b60", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "58c3faea04e4a21425555afa5486e2f7704c8e5d5773cda73d618b1049e0575d", + "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "6b16b89b4e7b3ca9ba6ca7b0ae881aeb7c81a450ff4f32eca3d0907aadf10fd1", + "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eb504aea2b96402b371e7b7bba7cbc5fdeb9f470be70927b11a340b5937513be", + "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c78dba1f0c58a7e8817ee9d5ddeb377e087432a1375ea3d99ee27b4a9f7d0ba2", + "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "4d29aed70bd5df7525c8c8e8d88cdabee235c229821a9adba08c38a3a7e3b967", + "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "2fdb9c3c42a3c97d3f8eec7b0e4bcd7a6db24abdf928d51a3c645f24aa7e41a4", + "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "afdb95f020eb318ea66b3150593787ead14f1e8590ab950bec5516d1641c39da", + "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "f1156f6f02262d12c777cee11d02b9c5cf9b4f28a27f4f9de9c154a8843d3d4b", + "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "aa972fcd1411e69464233fc54f34ac09aa04eb593410c7345718495e2ba684f9", + "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "ffa60e4ef87e7bb7229be6cd14f562d652e30e5badaa5892c0a7bc9563c56fbe", + "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.gz": "cb827715805de35449a17b190e1cb978bcd7d8b0a5501fe06d8f4313dce5b06d", + "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.xz": "63bc1122b296a89371d4a3560c06e1ce2f3a00482879d0ded87bd52f87fdec9e", + "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "b4d4222040865e4aa1d034f85511f436e08a1502c5213b6eacaf103d417755c6", + "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e1d19f8de4278c01914d3999038c49001c214ab9ec5286beab327322d30fb564", + "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b82d0a96510ca9933540bd8fc1534a1f91f92f92512a018b10cc007240ea13f1", + "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e4805b270f9763adef25a0f970d28d2d69a92ddd9ab6d7f14fa746ad61b4e635", + "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "f3f9ed7f57299511610bf0d44abc79d9a0cf994c979546895b9a42b72b17734f", + "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "08c1c3cef4f257841f9600bfe2f67312cd76fbeca1e4326963715ca77668a0eb", + "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "1a1bba0cb974217cbff68001c83270c631f13193b5e3227f22a8b32613f7d570", + "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "cb32c1d4addc20433b15751db0da67cef5bcc576c17319bd79566596c153af80", + "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7b6713071c93bdbb68f80f4045deaa8078382abe3179c60c92e0de5a0d93f161", + "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "313e6b05c3178b7e481ab09b71c1491b7136a47a9577649506823bdc698b279d", + "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d7d4dc600ff03857b60767c50a79c0de8a0a6a78ef3f309121b8338583526c5", + "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4b7d7da12ffe1ee279db21f6ef5b6124330ccee03711f3801561f68b303e15c0", + "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "154938148945148682bd165836e503064c248752cb24f1437d20a3ad128d6c91", + "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "be4c8a5b14fa9db00ad2f8efac052bbd6f7981610baf692b1d01f3bfb3be96f4", + "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "9ed70575f47e5a6bec063ed19eff165e35efbf6941403def15e48bf6560b949a", + "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "ad90bd85638cf26ecd72ffc0b09d1384c64fb990b4aa62f69e39d205609ba06f", + "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.gz": "54f71eff8e1ad3d22f49106b2c7b04713e7927a3f54cfc452c61e810e2b57129", + "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.xz": "b3f136e3d2bd5776887fb0071bc6434a1eb2cd42fccfe95eb8a32ca1bd36de29", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e57239d7d3b889ec4dad8db20bbaa0140a2f0a471ab62e4a1c48558490f33d36", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "4f14c69c15e3038508df42e254027f0b59ed798cc26f0952fcaa8068341fb55b", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "2898e0a9dc793fe85835b8167b8e4e4cd4d0b044fff37a85034624a92a8e8f76", + "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "667a8a268fda0c44878498b2c68239bfe7387d9d8f9d39ec4445a79409e65a1a", + "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "da4ab4baae0f241653591c0f69091724ac8949b18e261c69069ff368f86e76b3", + "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "333295a07edac2f7aa9acec4284c3f2417ec764a9c09e8735ebbb69621d80aa5", + "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "3b0899c1cdeebe01d8dabf5d0cd4f9762c07012e874111c77909840f917295d0", + "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "ad698922172524912ecba24c966df6bdf18a21e530c2467d835c297709f1f413", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "f9efa10a31e31857644ecd8877b08ae96f80962bc96efbb374128220d659c2c5", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "5392a4bc11097ac95e208c9cea7b0773b966f713f3b1e0ba42f1323484b1d27c", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "a6177b8b69eb5d4bd3507d50054009734854775f8821b74b6ad603cda1e0b351", + "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "33a00ce744789c49438fe8accf40a17c99282339ca69adc7a3e8a810cad9f1f0", + "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "4b042e30402804c20abd84b39384b0b7d88743d27a9f0a34f90d7626f07a4f47", + "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2e9fe2e92129a3952f1ae32760fd818a637b829a575194b84ab6d793d74c2c04", + "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "031b3c2134e2c54aeb29ba2e46a5b6db11c65ff3a364cedd14c79d741a1f9ddc", + "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "55f82ac681d5c8b6f0777939e747e8856707822e34b3060e9a85ec5935c8a406", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "53cc84de66c0c70b988b6136aa55c4051e51d27952e67db066ea409d56166fbb", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "6e9fa64aa157eb32e3ea4deb8d42256e5bbfee5fd4dae111f107033d792d28ad", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.gz": "d0e27984f1a2133af4e2fe9fd79a22f3e8a792a81111a496f80cfd9f3019b5e0", + "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.xz": "404780fc534501fbdd6fb34aeb3f338086feadebfef420a9530c6c4b48b803bb", + "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.gz": "bdafb54b1798812a0144029c421cc784a441ee82fc433f5788712f2c05fe4391", + "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.xz": "198be344c4a1c4247d8fb21efd9c84787272c0ae6208b341cae508adb8ba0ca4", + "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.gz": "9c51ebdba4c211050cc8c6733e21faec7d7fb2591abb38226b0593f449d7e8b2", + "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.xz": "f97595685703d22b0689b3f2822b3f69780eefc74a3169fdd1cf1d9a4538342d", + "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "2c32867f2e8ef81d1a8b0b3af14055be79f1da6dfe514155c9f9fd1eb98a99bb", + "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "bfc34e4077ece9675ed044a0e518bf8c38d0f351b62b6ea0d674f0c77c7af671", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "547505e533d6654d33df44e362cb421ea8fc69458efe51a357afc3665e19c826", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "f14478bd5bc6fea393111cd6f2dbbd1bc5a8d50adf0faa95b6d804c882d30415", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "ed17ac700cb1e4e773fd832c59aec036cebad714009786fec422077af35336e8", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "32b670e1e29d50c8af4ec0647b34855a07f9ab7a0142305a6a629cd4124c067e", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "225d33281ca9c69c3cdea76714e0383ae543c4f778859dd63cdd37dac09fa9d4", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d55f5260e2c50a608f760d50e7fa653284f2a8b8a64588a80dfb13419061b014", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.gz": "3719244c77c4d5870accfe562f30a9dc3290a14dc3da399e64909402d116c482", + "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.xz": "78bb343bb519070c0761ea7ed3c4e56b6d821095ac931ad7f812743600dffb64", + "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.gz": "452973239e8c0995a8b9522417e020b883f2f4052764b18b8cd50c9d08cb4f14", + "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.xz": "b1952ef69d1c4c32bc0aad4b4beddc6e6bd56155eafce1ffcaafceff8cb6d77d", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "c1ad87f6a2f4e1bc1eb2f732285546fb062faad9b27c4dc248ff174e4a2ec60e", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "ef6611b0ee43efdfc0a27dc3a7b65eeb8cba0d10624233fb473d521392c7d3f4", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "4efd4c3e06a3bc3c2f873901a956827e69cecfd38ed62ba1d8cfaf979d6a67e6", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "2c99a7541c6ca5b1c1fad00e76736e74d7ae50af3cd891aeed8f4f8747d4292d", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "3d5c2be1e0e5b4ce33e2aa4765e869872b247709db1b194512d12146be439c80", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e0b7e25f78e29a62d05eec6220000bcee815bcda24d857225ae47fcf3612fcf9", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0639d8e52de274f02f34ca547a2c692defb329bae290a4ee977b05e9a3deca52", + "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "256a4ddafddacad0024be539cb038e7742b37f34038a774a06e9a43b29558d5a", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "468113b22041adf0b7746838643ee316063f6049c20d499aa52ac2d9241091ce", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "5b614aa0b7a360a8ee79bb0dca0b2adc3cc0b8f4f2266806bfb0d07b811c11d0", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "d13f0a0abcc35bf6ccd035ba9bdd5b0760b995c885902bae73cf8a22cddc847e", + "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c7ffd2f6df10e754480bb1cb84b823084cf95cb6bbae2017437d5b9ffcd90b77", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ad94a6356dbee95031bd943212eedc441d596cb11da1206010cef611e436975f", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "b8c78492bb88d317580d01e96a70d9eb42d2f9f8396806bd810e348706924d25", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cd09bcb2d9d9fa25ddbcc81d9bf2ed2e68a177a1d61e1f9611516c95ca4f5e3e", + "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "efd2795a1484cd7331cbd849757a3b6cdbd50ae466bff760d9ec8e7ff965536f", + "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "10ac8daf897263a1c51f0ed9df13f707261048c6d11e7a024470ba71c3d3ef34", + "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "3968db993db3c861856dfa0974207b0709fba871cc17bc857c29f59063af15e5", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "33d19cbc173f71771b7a00a009789eef8f0b2cf65072642e0689bb86b191df4c", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "e896810ee1322ed011d662678839161e7c39faa27f1a8af963bc0a1e3b40a88f", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "d6b81169c6b77b7b93e03ac2d8289539e7ce6436106709f63b79a195b98d6fe8", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "6db5dfcdb0bba850db005a11e76cb3750befde0b6ef03b600c3c0e67a4c5d46a", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "5a729bb3471ccd07de54ca8fbc570fb617d4ba059a620754becc7aa48620f092", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "deb76d6f0bb0e4c9931df9976e869dcfc2548a851a06db89d656856bcab4fa8a", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "464bcf3a881d107747e241f88e71361dc5cabe7c27fe0e0f370c7ef90f8b77ad", + "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0b66291a56ea5b7aa6b194fcf08d844a067940a3ec4cac11a377c87947a5cf4e", + "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.gz": "583e0b2e03386dcc0397dec2802659937e73dad04a52263218128ee2bab8c412", + "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.xz": "b9ebb07f4b461cef81b5fbbb38ac89245f4df13215fc64ad04e6972c1c2d405a", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.gz": "12a5b49d776cbdb26a1a6c1e2c38d62f562cf9f99fd4868da317b08d4df1bb84", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.xz": "a1b7b2c27236e36893056dccfd9d15db906db53e8c0f931d1dfc9daa147642a0", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "9d1f6a6694e82528a6dc98d94f63aa253c0f2eac2cf1e9db97fb1fd9d9e68f46", + "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "179e6d158a2f27bca2be54059414526de20de76a9eaf26c99e01ef9b1c7743be", + "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "eda6db1398471b8cda7b7449ba86db47587398c7b322e995039f59caabe8c815", + "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "9a079f124309edf9a187a0980b59085f5a1cb9c94236154a9f53cd7ca67a71e9", + "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "af4a7d3da748a9f2ff867fb7e6b87e0b4696904bab60a2e38df21cf41c658ee3", + "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "420801efc6deddaaee5a7e17672e0ff520d965ece9a2b8aa1534d86ce839777b", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "82d3b6bbc71b5e138f8715bfcba5107f0d1cde6aee8fe6bddaf85fa646ddf1d1", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1eba8240509d6d5d0650f7e8e42cce89246aa1d416b859db496013d83983d4bd", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "d846e2ea559ad467945369d8230321734cca6634b8d1a4088475f8cafc9854d8", + "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "d5d8df8255a252af0c3eb66596d42a6d6cb9fcf3036fa8ab3f85ca1f344394c0", + "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.gz": "55bca00de9caed1f5443592373b8a2581b1bc1ade24bd062a8f2ba396c82e520", + "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.xz": "4db58c08b4e58584bf1a38205f100e0bfe79a74a4ff00280d5a29a3367302ca3", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "76c72088f1d77d84270b8ad00ee87a79cc8607c852291c5d2b82f59e6efd96cd", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "17eb428984599dd696554d9710cec60fcb01c8d341c0e59a0c1c00370c0d9c72", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "9dd0184f99be287f318952ace8190af2cd7accc47a7b3f388d34c77cff60c5ae", + "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "d76d255d3db0b9a5b5e8b1670b3eff4feaed8dc938187a6783a3323fb4998b8a", + "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "8f8d60ba72543402b0c62bd68192891ee290fc7daff104e9ff8b10c9d109d791", + "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "030629f57e1f05c7a1e96a147f7a2086c0968a6abfecbd375f9093c4a2859fbb", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a5d01dba11d59ac1a11404905c54425594bc69f40cad8814d3ffd00d1b38c52a", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "5f2ea9f7e62fb429f4f0575a267eb46a014b9ae727939f909ec5e3777e32e65b", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "6e76c8616ee86d1b51c9b055b324f715c1a9cbb1c1564982d1f7e6fd623cd292", + "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "54641f169e424a73cb386e41563af5ed9ba833379edc148579f67bdcdab281ba", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "64303412deb9264dfd15a16341203df39af2e9206ce1d22ca5eaa83762e1f62a", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4c4cb3fb0ee51f9294cb805c7263f716a921e7d76503cbbd24f8600c485c58aa", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.gz": "e197dab9c9b11cf98404aed094d1d8bc03a6755ebf4046423c11baeb0143f254", + "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.xz": "81a80fa315dc3da8111f487b9dd6dbe56991276fac138de4469c0e0b688bae07", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "9cc065dd7fe550716efa403c910d9eaf8c18d90d7d3e316772fac72f7f16c45f", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "6bde95f6c57f6ce4de4f1ce9837b386e374eb291d8778956bee0956b150c3917", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "1262105c31f7ec6248b24b71f0003014a8558220444cfc88c611ad2aa94efebd", + "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "cb35ba7184ba5a74f5d6c8592e67e08faed205e091784f85137872e02541ae99", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "31d7af84b431c9185b2ef98c18eaadb957e22e427b331a8ed4ab8b2b6ae364ae", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "674b1c886ae4a2273edd6e49539d45a2a02e73874f6a65ba820dbea75d8ca8c6", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "cc620438e90fbd086b4f237454b099a81e4cc3dae9582e7526b2a10648663e4c", + "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "425ce38ad1bb048756a37e8642ab6b43f8189bee244e4ee011e95fd45f3a3747", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "40b0df32d5df53fe8774000804738d56e7c8768cba1baaf52721a9956d62c557", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7df34f8ddb1b14698c6473eaaeffd5d6da23ddcde23a74a3482194e01fa5ace7", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "65b3db3bac29c8aad57c8cabe7fbe622acfdcd9221c11af4419d74c24452a939", + "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "9a4a382945631425fc8227d6b42d0f97988dc39c8e79646280e080595d82aa31", + "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "30fc151ae3a6423e027aacd70bcd45d13243aa5394ff2d6cf285c55d3c5c6e23", + "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "28cef1191d2181004b8e5032bc3f7b548996149dac8ffb5b8a5431b32d396683", + "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "a6b79a07cdd6cd6d0e468132ab504464e3d6c41f28111cf15c6053d7d560b8b7", + "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "67aa93c917f234b0b61dbd3fac21a1d6d4ef20cc8dd7fdc6a8bb8e688e3920ca", + "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "e4dd3483a85060d75a7dff95dda7a121943f1121983e5d33eff166f4c3e97e6c", + "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "36f2b7305e8ed58666c206c26e28cc5e8708fdf104f1d67dd0c692f9e36a1482", + "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f232913783443410614af3e27a832740b06d392563f5d0aa6d0ac0558d7bbb6f", + "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f54f1f0c7fe7b31ff97bde512573225f7380bd1c35876862ea798fc2b38cd4fc", + "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "728135a1f7c89a129c78c2adf360ab06feb79f28b10f993797d498a9effab9e9", + "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "ba91db121409dc9414377759fd27e8947e46dbb9f3788521d82a67b063c2a9d6", + "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "c092940c2eaea9c9168061b8f5b87f1b735c1d0ffe05bc834252719c42f3ff33", + "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "2906008d17bb17bc84709d8e47c8c065b2749355240e630cdb1f0c173721a05a", + "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7815f8bf5838e2f497e2d42cad55c3e738f64957e031af90f82d80fa7ce78f1a", + "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "16bbac000585cc3985582698b42635d1e3af68445e2ef4340600087e1fc38e26", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "2fdb717d0fa4f3e162ab8603d2b5233c6ec20a587af874d0987b1b040ea95dfa", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f4f2445d1e9f8cd0af34ce0063a44041465df0b6d5b73546595d0d37f0342087", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "a2df1578a4ec47fb925102fd6604add216ed7d27bdf323176328afef48f2faca", + "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e3839aa18e35d7d050ce00210774a63b84b3070bc28be1d70ffd4c939b6d8cc0", + "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "4ad1c23982c5d5b45935e52fc1a0e36e08e853a993a0adb5c9fb9e703ee2cb7f", + "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "1308041c43eca228f265cd1cdb3d419bb7e4e1461e117536b719cc3ec8527798", + "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "0fdbbe00f9b655e657d93e97bd1b625afd1531249cd32d013c0a1d62e48fdbad", + "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "cd9120d576a533106721b11e4e457c317be7ff484613d2c7592606a379c0fb3f", + "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "c570c55584f9d725c69bf092e0187dd7830839b6badc6fba62b5fbaa19b75548", + "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "d3e63b5f8f139e32a40ccbc7d877714e88d68a31e1644cf4d1cc91771d5459c9", + "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "61169fbfdab7d66712f04a53d6ab8766766158a566bf606075132002a67bda0f", + "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "f137dbdf000903de091c076fd3800466097caf2f9c48e4ebae9c3072fc2aaca4", + "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b81429647fa2fd42fa7a5b4c15d15b1595023e81a7e4289e06bd214c6666127b", + "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4a741ba60918138ab24cac1d6fda432d38d02bbf0a22103270df13e0d40c8a86", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ac20977687a1831ea2883568eac148821ad9f1ad199a9b728447f7d15f518e1e", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "57262c3ddf2351b80ff8dcc03fe8e16b441e1b0014c0e4534e2e493902928ea7", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "be9111bfcd464b5f107642b18fc375eeea16a1d758de71cfb6258e0302c9ae7a", + "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "63f84a900c52caac4eed1c58bbfc604e591c56e0fc1afcebe7ae832a9610c060", + "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "51f5266d9790f4e691493e403edcd664541afd448123fea3fbd1de2d50c87f1e", + "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "12f7be43c58de67c761ed17bb555509e639c31c5cc0783d9ca55e78c4586317a", + "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "37f3baa3a2db1b15315915910447332bcf5b9f36666f4cc08868b551d27022cb", + "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "e1f457d3da72a9989b90395692310c78c5e5fdcea35fc1bc2f450eba62b7d21d", + "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "77a461b06eff56bc00361e9f771e0a81087fed2999e5d1f2f53632a61e90829b", + "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "29a4f3a426e380b886bc7a468b08d2dad38ff704d74ec2f243ba5ba7720c7e9a", + "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "cd0285f0254f4042ee70f02ea576ec713e34ec00e2fc0309cd7c891ca26674ca", + "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "43dd490c8068897a5f45ee0da36ea8854496cfb54faff9f759e2795f22d46cb7", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "cea8f1a52c3829f4781c321bb43486e44ee8fc94602249d1084e8a6e9269e2ce", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "9a6b827b4958d412d4f413219458582142d1536f313d14ded54cf666a43946bf", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "a032c778052e77eb32eef136ca431ce2bfbd6e43ba5a82e90b2ef3dd414b2cd0", + "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "cb560e7b3c62bd2598e701360b11a6edb16e730700c4aa5e5d284dd1ceb570c3", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "c8e3309f94e8187e41d5de922c7988d610439be3a90e06c9eab76b4a3850343d", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "f1388800ff04b85fa549191a5cae8e4964baff89ddadd57fccdef85a1da99e4a", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "c0a18d66485400b692011d72af2226fc609eddd19fd1e95f370ed6a864f6dd8a", + "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "f3772ae732dcc6a63c2143d3530d8253b35c7412b2266ed9583d14f6000b214a", + "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.gz": "aa204e3377e1c4272c18231bcdaa439678fbb1158d794ee8b2699fbad382c828", + "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.xz": "25c90365da9be1307e4aa80f699ed14eec03bd48b8271570d9e9e9d4dd0f701d", + "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "24754ac282a434638de5bd2a548b3960149b811f03422cf875a5018dfb229441", + "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "0806c72137fd994acfb304039af85e028999ab941d3d95cd037f298a66377aa5", + "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.gz": "588bd3b637531ae3399a91e805d52481c927477d15822636714091d2371e95cf", + "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.xz": "27d75a39fec3ead30dca470f0f6c96561a48bffa8d22c283001f7543b0d62f0b", + "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "b7b32388857ecd8f1f16fdd5354a9411c84c463b8b40a1ec2982d5dee11e2318", + "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "5ea72074aedac44961823a6a8788bb7aecb905dffe2c25d52c417275be39676d", + "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.gz": "5f53ff113fa233161183bd1c79a946aa13770f52f08ab3d8a62a080ee2682163", + "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.xz": "5541a85df4ac431a14830b09bcda0d030236ea31419b1ccfdf2e761638a1c484", + "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.gz": "d17d49d6e416941c1aeed7d145b47d2d61a7bcb563720ed5dd9b867cd0522f05", + "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.xz": "41aa64b361c17afd7466b621923a44e80d61edefd7052e06df1eb96ee0cad3b1", + "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "2527ecd6465989f54570e7ed61b51c8a00bc5e1c613e972c93b028df0ad60ec5", + "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "91f243a73494de90c5250a663f111b3a999925a923cb92220d1853428e2b1aea", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "e41010c4f7bec5b06205085fba4e538cec40222c18c5d560c2a1a2f5c2d4b859", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "af8185b065f2ab37f92ec671eae1652368b26b6917e34c24f2a15779f1e447c7", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "1fc3c51f18174e07ba21bd8bb4da495540273ac3f89d2e106172bd6cbfd08ae3", + "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "b5ffbbda960fd38bc11bf56e154990b385940fa6fd95563feed0a403317aeca4", + "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.gz": "8bc7de9a99c3eb1954a1dfd17a39629449e41d743ee85437dcc67f37ccfa9cfa", + "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.xz": "919ffd2e0221c6e6125cecf5f1c21c4b03d3e98c4e1322e5ec664e4079d37fce", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "fbcdbf0d7a8dc6970fadc835455a6fce455ecbdb16ec435957e19477efe94af6", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "09bb9ef104f7eeaf6fae591d908a0f8cbaaf98f1a14e788f468cf99dcbecd8ce", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9b0176f89bbff3c2fef94ca3731dbf9e3c079288aee88827efb42a6296ff8168", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "d84e40868ce185b39a0ad9a6dfc118b31cc0742b9e4e80b59944572043088f24", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "69cb1a75f109f1bc3ef55eacb2bf8f3ad4e4f74fbe7fd2b92ee448082b15292f", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "de2bff6b876d38a20c944b9ef1ca296061e6882080316cb6ad4f346b3f25543d", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1e7803d70fd4965da58e0949f1de2ed9624852b48a6afc43fa7f007940e1ad61", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "cff451b8636469879061f9d0a2e2403d3bece99ea61e4ce8992095dcc5d57429", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "42654d72fc9816827ee0e0fba553f672eeacf7af2f828dcced42b3603ea7b244", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "d8b40b941b95d888af07649aece54b51fe419f129957a3c1ea00bb707092fba9", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9e168ccc151b0320feac61a46f69e5287ebe61d5cda4fd096c2a6e4c1bc4630e", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "1fa18c0e9d352188505f1dcf21b132863cf531f3a5d1cec512baaa135dae071b", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.gz": "221da3b26cafafb2f1db1bcb69529424df021e149983ddd07cae15f9e7bd3b05", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.xz": "401b277ab48e8b5dd30da993a68b2318b9f5c3f6a1cd69c244dfa62212b77dc1", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0a67ac955769e71b677af6647233bea61f2bc61db0eda5b3a2d70fe52c094806", + "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "96d52cf2a502adbb3cc37f1c46fba79ec7dc2ffdfaa369e58ba60a2e9b7a6efb", + "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.gz": "13c5bf14af21282b302efc63285b2c683f24853d510319aa43d150fd127255d1", + "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.xz": "3afc8778d32d04b8137552ca651237b5573149bfb7c4b3797e73746af8636612", + "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "84f95488f8540020efc1f59d3112805b7b16517fcf0e991fac45757f7f88d09b", + "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "818479235bdc06809c89728ba7c449f2187c159aeb45ffce62250a1e40202921", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "1a8acf7bd5d81b0cce741669aa76170c595525bfd981f327199a014d8f96cf29", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "eaecede917a4994772b1043c42c1a0a88bbf0efe5b9830e5be4fa039c13152a6", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "f38e0aefff50338ec442a8a915aef83bb89a445c2535840a74cc1cd3ccd0ec1a", + "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f4c7ff3f19303bf82b0a7e3adff2f1d76be75487b78a53a23b5a564567c418b8", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "473936c8d1c6fb7de9da593185d6d3dcf32b3cd833e9a7b96a721ce6ad587628", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "72787fe6ae27c684c166acf178556ff570a923db89b5e4576b97b528b991b6db", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "f641842f5b298ba11d7143d4e24f03b8adf20363e25c459a9b98e9903fd48a16", + "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "3ef2c162e55a62024e4cbb079f03a38d40529d864ce4f8d28c12843b38568802", + "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e3e714078092863a7cd3a6d9c8b8d8a8c05da97debff0545f45593163bd51e4e", + "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "dc9ae664ffa5b61d576182ddb79234331e1227302fe9cd6db0926011522582c8", + "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "9bc6578d355c1fee74e8104331cdad4f3c9c94bf1713e989de5d52c1f5291528", + "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "412a2ee2a94ecec20c1c54934b72d84b46e29f35f6520b8e654ef518b9a7e511", + "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "f8fc7fbcd82398964ec562f0750f33fa1af55268e053d416d0729b466fc7fb3f", + "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "eaa66c5680987aaea99d7cd38a5245c832698f4a53443eeeb06880a8ec915497", + "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "8748755c8c72ede71310f998c38ea0ba80e2065da5f53f8ac61bfe8e4c94ea1a", + "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "fac18aa72b3c801230dd3a653bab76521618be5fe48de2f79dc1890dacbc7a9c", + "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e22c7209d77b1fdce3439225c2e7d659a61cdaced9387fccaef5370cb25baef1", + "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.xz": "cea1aa2447e02cc6a4be215f0bb4b658560f641389e314c0cc6814c2e1cb5c18", + "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e57c23dd8981d77b81b27af2879c4a2bf9e6619b5a638d8ba9dac790bf9316a0", + "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0dafb1d812358f5275ff272d247573ac0799dac64a446f7ad08543d6f4334088", + "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "bf6be111afb4ea7ecdbc611e94aedce8e5ebf255f1e52cc61da65913a6963471", + "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "7d169795f5ef7c09b7e3a9b40d8669c0b2fc6449247551b426286ebe3f6e258f", + "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "0e76f229b0dbeb14497cfda0f4d717c369b8bc59c7bce1fbad059220562c0814", + "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "d6870a46ab49264498b18a4cd2d2400f0df8b02514e92c1bd6396c732f869035", + "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "547269aa65cbfe33ef5457ac969399fcf90384f57523a91e9c61306fb9e464da", + "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "fe75b0ae3a9338f1e48e72e6d6f51edba25f5fd7ab0544d3feae6b69105f160c", + "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "b445b6ec414be5c580a19717125858ed4c8e0c90828e085f2ab47a3b44a0863e", + "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "a915c1da4a45cd286c0b8978999d5ef2ab96b24185793ee1dc043e094cf6c51c", + "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "72b6014c14f12f5e5848924e20342d993903d16e883ea8473ca8cf9d188f68d5", + "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "ee707cf657c9991eca8a9b722fb58b420b2c9fe9bc9e32c4042a4af2bc37e8cb", + "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8e1fc4091115f93f13d88dd7a9b05492ffbcf72f12fc8bdeac28dd6f3c78c3ac", + "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "ae52c2a0c43871c658d63c101a192dd5fea65931e0d45855bd8dd40a58a7e688", + "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "fe45b4d1d509a7a0c317888b575d3dcf1dfb7c0b8306ec54e2d09245c906e276", + "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "0c06412d27669429ff1c0e5855c3a3ac923b40a93b2fdcb8fbccb4033476b5d1", + "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.gz": "a3c33e87a6b12049fcd7cbb0f53ea74c8411c91c262b6f352a1024221d3457c4", + "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.xz": "3256ad9fdca2506b06962b4e88c9a41daa8f094a5c1c80530fbce4dbdd6e1c32", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "e2881ef537ec43fc012307cdac5291e4733b322e92a3b056a6f2820c883653b8", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5a8a36ca5f01ffc8a2dff21c6fbf99652444c6d3731c650fb91cce1fe79c3ebc", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "6ee9a6511fc5342b4f07102f874822553c928ed75f09c4e34952db1c248604f1", + "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "830d24aff7aac91a61143878969632a47eb8392c539fabdd25826792c7125509", + "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "1fb6dc34083e95e193c39bfb4edca99f42713f5cfe3bda8e368e977f61c82110", + "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "c3b9ba1586bb6152596aeb01997b40ab65ab7140525b1b0bc22f2a84baf5c44b", + "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "584b8ee47755982a6b0f0d0d5a12af35ad740e2df8b1ec1d3084509ea940c2b6", + "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "a4532b97743b8a90f4f492513c7cd51600426c08454be2e24a49cf867ca0e30b", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "f3fb7f949724bf9b8b77cc562d9d53eb067872bc312ceeb2b5541c6667f70da2", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "10912b2783699d9e155b4f59dd762fe012e4ea4410b56d83b36d1df769a8cd49", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f548bad660bce1513081be0767305a523fd129a0b13aa368e8c86a36d1ec3b23", + "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "fd52405c614d6932d9e5948e851be7315f1f9d21bbfc3e6d142d6d3196464fe7", + "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "1b816d0bf6d4138bd557094f922e7aa9b2e7d0ea27464cadbb117eac8a42f3fc", + "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "b869ba4ab920cd08bd063cedba08614d5c6199f643d277d59f44af513925c16b", + "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3ac81b63371115875eec194eb4d0c3e9aeb624c7f7ce3ee85b197b8e3f1cd599", + "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "8eda09837e39a0847b79803645f810d87be7208465deb7f5b0952fa7e39c2113", + "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "353d2f523a3a1bc2ca478b6facea40363d2d18ca6b48d8f4be18626c7cdb3142", + "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "ade013031c8c72eae5717c248cb20f36107d326c497b4f3c8e90dc2912d11975", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "64b5f8f97781bd4eca5554f28688a58831162fafaebac31b0f04610e16f09a48", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "feb458ae9a30773519b8be69557d0bd4c3d924aa22eb4a4fdf331e0d620f1e90", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cb2698b870f2c56554996f2e651ae53b11241c06da6ebab4b40a460f6826d91f", + "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "b0be127f8c04dc4ac2d77b2f9ec7e74a793b65bcd591c0c6a7208b1f4b445df3", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "596b02cf564a03c69a29f61ca6bba4758152d64775eff62b767bf77cce3b00bf", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "f819a48640599ea06bcc4a3f3630bd0a12c9e698cf8f62f61b36813830a54d55", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "19df36c566a4cf5d440011a1c0e94a4cc70e5b66e29b36a268872d4e2def8e78", + "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "dade13d688c6ba9b291b403d4d61bfd8973d3284b9bc7a92ed6de47665411f07", + "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "5ba3a696872e02cb2a4b2e191262d61ecbe6f289345373ee06c542a2d2580527", + "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8ff08027f040bdf0de0496d6a408796fcca44540b097414255f776704e6f4966", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "15a36d3a798d2fa027d05229ab42baa4cadb6faa8edfd8c13260ea4756031194", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "438ea44472607752d205d9d2f14056a4c66fd9a84f728110792aadd22929b9fd", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "734aa5ce2105134c34301e44f7d8f0ea3bc94587df3e27793530f3a722eb9b26", + "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "02a7401369a03caec796deb2d3a0b3c1a46bad79bbe6e654d9e721cd95bfcb0a", + "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "17a8c573eaaf5033b15ef14ff221848e3100332b6f01b30b249c9e854bcc21d9", + "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "bca6959f1e6977cccd0571bc61a37928f559eee8e10395d7eb033cec9a8e0dae", + "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "6a4cd4b13e877b7f8ba712cab0e804edefd432d78cd46970bd44384ce94e7faa", + "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "43adf44181bee2b295584c36c35041ff97465fa3fe46b358e142a1d10c224a40", + "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "376abf3aa462c0e1271044761af0c9f3c63442731c6d04accd32a0ca0221eee6", + "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f8a5f3d01e06f46a6d85fa7f74b1a494fcb55a6d5dc8113eb96d6a46d0d37050", + "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "158573b8e9da4e8a464bd3c692e54084cd0b9097596d41c21646091883d15b48", + "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "bdae49f025be97fbf37c9ca7ef1f4331ec4ebf8a5fb429a4c20f09619069e655", + "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "6ed1ea2364c8b645c6d899cada76cf161222fae9b4693ee71fb98721409f73a8", + "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "beaa6383696385769cd885b3314ccb6f69a7a5557bb1af7214c2c8b2d03d64c7", + "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "0f0ad140d47b4477e9ff0a925468b36aaaca0063eed018022624ee15cd0fcd7e", + "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "23d3bcf9d9a22bd869b3857c7c8bbf25c168ab60677a958c8b48d8b04319beae", + "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "fbd1655d0399a3e8728710dc0c234ebca2ce8669fc42eadbbb075baabaee740f", + "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1d0c70f5ec38542f2d5b125d59d93ffa1a984a7a2e2353503f8b8554604daa8a", + "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "34acce36d8aecd8f4414fae766c2ad7c7942eaa8b422075017ce28e84f08fb08", + "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "8984ea923bf93c394ca50b41f58df0d750bc522c481de2a0468afafef052f343", + "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a9064c4ecfe40a2b3cdbabe12b6063f13680f2a6eb36d58f02fa6207af988a13", + "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "3576cfd24cb1b53d96145651810c532a5b1c424dfcc39b2c78d5688d7f0791ca", + "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "2b921dbf7f8c2931bc531665087ffa05efe8bb4270902a311789409994844cd0", + "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "f6a4134ffb2c4616606b5d9d3ba63b9dda1ec49c2c0af2290a915c08d80ef301", + "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "468bc3d0d587b37993cda14fbaf07ab4edc05627126d96d9ccaf58b1df55178f", + "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "e6262f053b2e456d09ce6617e8209e229d2b9ced144a9eff12de830b6f0cbcfe", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "34a9cf74d9076c49c6266d718fad9a78ea1ede268f9b7978b508b76a4c6e3f8c", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "3d0e544dbb280e4cafebc05dcc68b3cda8a742f9909f59de93c8791721c3f2c8", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "d7119b250b1b31fcba6b3d34cb8deafa32fe20f547ad1bc1e931c58e7059f65f", + "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "ebc31e9118112e64fced1ad94e4e903e7ac0ff8dd771d85a55c1589a6b838c38", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "a940ea208faa9882808cc56a8e96cadf79f954844ede160b2b8971238bc84f4a", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e699ef1a7a7f5e4bd40cbb3daff754e9214cbe71c28b1436a893a5edbca8c876", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "2a53b4b5e57fd9e1d9014d46576e6b47b51d0dbaaf55c4e84964390c2b2065cf", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "e4491027e20ac563ea8a0906d8941f80274890d4d1b4b3728e26e5926f2c77cf", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "b7ba70b0ca5ece6b14cb1034e7226a83435f8b71c77a864b4ad949db11ab75b1", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "ce07cc2010a424e83672095d89b4592485a7c94a3f450e609ed62237c86909ca", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "bd653ae8f104872e5a2f937fabdff09d41691c28d512fb7f08562fb21ab64e89", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d374ef3fcfaf21c13813cab8953c42c9c965c02549d18e95fca903b923ef5e6b", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "f0fe5175ea73034b1b789db8d31214ca561af0f4be21c52895b47baf103e5952", + "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "6bc6231ebba38ec47fc1de646aa7d8a9855d2dbfb61595fad299656e39acd0d5" } } diff --git a/src/test/assembly/align_offset.rs b/src/test/assembly/align_offset.rs new file mode 100644 index 0000000000000..c5eefca3467bb --- /dev/null +++ b/src/test/assembly/align_offset.rs @@ -0,0 +1,48 @@ +// assembly-output: emit-asm +// compile-flags: -Copt-level=1 +// only-x86_64 +// min-llvm-version: 14.0 +#![crate_type="rlib"] + +// CHECK-LABEL: align_offset_byte_ptr +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +#[no_mangle] +pub fn align_offset_byte_ptr(ptr: *const u8) -> usize { + ptr.align_offset(32) +} + +// CHECK-LABEL: align_offset_byte_slice +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +#[no_mangle] +pub fn align_offset_byte_slice(slice: &[u8]) -> usize { + slice.as_ptr().align_offset(32) +} + +// CHECK-LABEL: align_offset_word_ptr +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +// CHECK: shrq +// This `ptr` is not known to be aligned, so it is required to check if it is at all possible to +// align. LLVM applies a simple mask. +// CHECK: orq +#[no_mangle] +pub fn align_offset_word_ptr(ptr: *const u32) -> usize { + ptr.align_offset(32) +} + +// CHECK-LABEL: align_offset_word_slice +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +// CHECK: shrq +// `slice` is known to be aligned, so `!0` is not possible as a return +// CHECK-NOT: orq +#[no_mangle] +pub fn align_offset_word_slice(slice: &[u32]) -> usize { + slice.as_ptr().align_offset(32) +} diff --git a/src/test/assembly/dwarf5.rs b/src/test/assembly/dwarf5.rs new file mode 100644 index 0000000000000..f41e6bd55be7d --- /dev/null +++ b/src/test/assembly/dwarf5.rs @@ -0,0 +1,20 @@ +// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5. +// assembly-output: emit-asm +// compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 +// needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn wibble() {} + +// CHECK: .section .debug_info +// CHECK-NOT: .short 2 +// CHECK-NOT: .short 4 +// CHECK: .short 5 diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index c97223879ca3a..260d9de867087 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -10,7 +10,7 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @alloc14 = {{.*}}, align 2 +// CHECK: @alloc12 = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used diff --git a/src/test/codegen/enum-bounds-check-derived-idx.rs b/src/test/codegen/enum-bounds-check-derived-idx.rs index aa66c2ed08edb..fe02aeb5f6252 100644 --- a/src/test/codegen/enum-bounds-check-derived-idx.rs +++ b/src/test/codegen/enum-bounds-check-derived-idx.rs @@ -12,13 +12,15 @@ pub enum Bar { // CHECK-LABEL: @lookup_inc #[no_mangle] pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 { - // CHECK-NOT: panic_bounds_check + // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332 + // CHECK: panic_bounds_check buf[f as usize + 1] } // CHECK-LABEL: @lookup_dec #[no_mangle] pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 { - // CHECK-NOT: panic_bounds_check + // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332 + // CHECK: panic_bounds_check buf[f as usize - 1] } diff --git a/src/test/codegen/enum-bounds-check-issue-13926.rs b/src/test/codegen/enum-bounds-check-issue-13926.rs index b26945bc54940..1aec41d54411b 100644 --- a/src/test/codegen/enum-bounds-check-issue-13926.rs +++ b/src/test/codegen/enum-bounds-check-issue-13926.rs @@ -13,6 +13,7 @@ pub enum Exception { // CHECK-LABEL: @access #[no_mangle] pub fn access(array: &[usize; 12], exc: Exception) -> usize { - // CHECK-NOT: panic_bounds_check + // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332 + // CHECK: panic_bounds_check array[(exc as u8 - 4) as usize] } diff --git a/src/test/codegen/enum-bounds-check-issue-82871.rs b/src/test/codegen/enum-bounds-check-issue-82871.rs index a1fa1387d9441..32fdc4a5f4fab 100644 --- a/src/test/codegen/enum-bounds-check-issue-82871.rs +++ b/src/test/codegen/enum-bounds-check-issue-82871.rs @@ -1,4 +1,4 @@ -// compile-flags: -O +// compile-flags: -C opt-level=0 #![crate_type = "lib"] @@ -9,7 +9,10 @@ pub enum E { // CHECK-LABEL: @index #[no_mangle] -pub fn index(x: &[u32; 3], ind: E) -> u32{ - // CHECK-NOT: panic_bounds_check +pub fn index(x: &[u32; 3], ind: E) -> u32 { + // Canary: we should be able to optimize out the bounds check, but we need + // to track the range of the discriminant result in order to be able to do that. + // oli-obk tried to add that, but that caused miscompilations all over the place. + // CHECK: panic_bounds_check x[ind as usize] } diff --git a/src/test/codegen/enum-bounds-check.rs b/src/test/codegen/enum-bounds-check.rs index 17322d5911b92..f85c6817deda3 100644 --- a/src/test/codegen/enum-bounds-check.rs +++ b/src/test/codegen/enum-bounds-check.rs @@ -21,6 +21,7 @@ pub enum Bar { // CHECK-LABEL: @lookup_unmodified #[no_mangle] pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 { - // CHECK-NOT: panic_bounds_check + // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332 + // CHECK: panic_bounds_check buf[f as usize] } diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 74b1eb948b0f7..033da80be16cc 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -27,11 +27,11 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> { // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: file: [[FILE]], line: 14, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], -// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: file: [[FILE]], line: 14, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs index 3ec860f2cbc06..9c9f5518b6649 100644 --- a/src/test/codegen/generator-debug.rs +++ b/src/test/codegen/generator-debug.rs @@ -33,11 +33,11 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> { // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: file: [[FILE]], line: 14, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], -// CHECK-SAME: file: [[FILE]], line: 18, +// CHECK-SAME: file: [[FILE]], line: 14, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], diff --git a/src/test/codegen/intrinsics/const_eval_select.rs b/src/test/codegen/intrinsics/const_eval_select.rs index 34e653b4b9dd4..db8a04763d35d 100644 --- a/src/test/codegen/intrinsics/const_eval_select.rs +++ b/src/test/codegen/intrinsics/const_eval_select.rs @@ -2,6 +2,7 @@ #![crate_type = "lib"] #![feature(const_eval_select)] +#![feature(core_intrinsics)] use std::intrinsics::const_eval_select; diff --git a/src/test/codegen/issue-37945.rs b/src/test/codegen/issue-37945.rs index ee63a783f52db..12fa1e9e56b6a 100644 --- a/src/test/codegen/issue-37945.rs +++ b/src/test/codegen/issue-37945.rs @@ -17,7 +17,9 @@ pub fn is_empty_1(xs: Iter<f32>) -> bool { // CHECK-NEXT: start: // CHECK-NEXT: [[A:%.*]] = icmp ne {{i32\*|ptr}} %xs.1, null // CHECK-NEXT: tail call void @llvm.assume(i1 [[A]]) -// CHECK-NEXT: [[B:%.*]] = icmp eq {{i32\*|ptr}} %xs.0, %xs.1 +// The order between %xs.0 and %xs.1 on the next line doesn't matter +// and different LLVM versions produce different order. +// CHECK-NEXT: [[B:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}} // CHECK-NEXT: ret i1 [[B:%.*]] {xs}.next().is_none() } @@ -28,7 +30,9 @@ pub fn is_empty_2(xs: Iter<f32>) -> bool { // CHECK-NEXT: start: // CHECK-NEXT: [[C:%.*]] = icmp ne {{i32\*|ptr}} %xs.1, null // CHECK-NEXT: tail call void @llvm.assume(i1 [[C]]) -// CHECK-NEXT: [[D:%.*]] = icmp eq {{i32\*|ptr}} %xs.0, %xs.1 +// The order between %xs.0 and %xs.1 on the next line doesn't matter +// and different LLVM versions produce different order. +// CHECK-NEXT: [[D:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}} // CHECK-NEXT: ret i1 [[D:%.*]] xs.map(|&x| x).next().is_none() } diff --git a/src/test/codegen/issue-75659.rs b/src/test/codegen/issue-75659.rs index d093c841d68ef..6bcb59affe328 100644 --- a/src/test/codegen/issue-75659.rs +++ b/src/test/codegen/issue-75659.rs @@ -1,7 +1,7 @@ // This test checks that the call to memchr/slice_contains is optimized away // when searching in small slices. -// compile-flags: -O +// compile-flags: -O -Zinline-mir=no // only-x86_64 #![crate_type = "lib"] diff --git a/src/test/codegen/issue-98156-const-arg-temp-lifetime.rs b/src/test/codegen/issue-98156-const-arg-temp-lifetime.rs new file mode 100644 index 0000000000000..12ace5fff6b6e --- /dev/null +++ b/src/test/codegen/issue-98156-const-arg-temp-lifetime.rs @@ -0,0 +1,27 @@ +// This test checks that temporaries for indirectly-passed arguments get lifetime markers. + +// compile-flags: -O -C no-prepopulate-passes -Zmir-opt-level=0 + +#![crate_type = "lib"] + +extern "Rust" { + fn f(x: [u8; 1024]); +} + +const A: [u8; 1024] = [0; 1024]; + +// CHECK-LABEL: @const_arg_indirect +#[no_mangle] +pub unsafe fn const_arg_indirect() { + // Ensure that the live ranges for the two argument temporaries don't overlap. + + // CHECK: call void @llvm.lifetime.start + // CHECK: call void @f + // CHECK: call void @llvm.lifetime.end + // CHECK: call void @llvm.lifetime.start + // CHECK: call void @f + // CHECK: call void @llvm.lifetime.end + + f(A); + f(A); +} diff --git a/src/test/codegen/mem-replace-direct-memcpy.rs b/src/test/codegen/mem-replace-direct-memcpy.rs index d1c4c56dbe468..b41ef538d718f 100644 --- a/src/test/codegen/mem-replace-direct-memcpy.rs +++ b/src/test/codegen/mem-replace-direct-memcpy.rs @@ -3,7 +3,7 @@ // may e.g. multiply `size_of::<T>()` with a variable "count" (which is only // known to be `1` after inlining). -// compile-flags: -C no-prepopulate-passes +// compile-flags: -C no-prepopulate-passes -Zinline-mir=no #![crate_type = "lib"] @@ -12,14 +12,12 @@ pub fn replace_byte(dst: &mut u8, src: u8) -> u8 { } // NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in -// the entire output, are the two direct calls we want, from `ptr::{read,write}`. +// the entire output, are the two direct calls we want, from `ptr::replace`. // CHECK-NOT: call void @llvm.memcpy -// CHECK: ; core::ptr::read +// CHECK: ; core::mem::replace // CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %src, i{{.*}} 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %dest, i{{.*}} 1, i1 false) // CHECK-NOT: call void @llvm.memcpy -// CHECK: ; core::ptr::write -// CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %dst, {{i8\*|ptr}} align 1 %src, i{{.*}} 1, i1 false) +// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %dest, {{i8\*|ptr}} align 1 %src{{.*}}, i{{.*}} 1, i1 false) // CHECK-NOT: call void @llvm.memcpy diff --git a/src/test/codegen/noalias-rwlockreadguard.rs b/src/test/codegen/noalias-rwlockreadguard.rs new file mode 100644 index 0000000000000..7f7b46c85a8b0 --- /dev/null +++ b/src/test/codegen/noalias-rwlockreadguard.rs @@ -0,0 +1,14 @@ +// compile-flags: -O -C no-prepopulate-passes -Z mutable-noalias=yes + +#![crate_type = "lib"] + +use std::sync::{RwLock, RwLockReadGuard}; + +// Make sure that `RwLockReadGuard` does not get a `noalias` attribute, because +// the `RwLock` might alias writes after it is dropped. + +// CHECK-LABEL: @maybe_aliased( +// CHECK-NOT: noalias +// CHECK-SAME: %_data +#[no_mangle] +pub unsafe fn maybe_aliased(_: RwLockReadGuard<'_, i32>, _data: &RwLock<i32>) {} diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index 381f11ff1efcc..9bef743ddcb41 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -1,7 +1,7 @@ // ignore-windows // -// compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src +// compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src -Zinline-mir=no // aux-build:remap_path_prefix_aux.rs extern crate remap_path_prefix_aux; diff --git a/src/test/codegen/simd-wide-sum.rs b/src/test/codegen/simd-wide-sum.rs index fde9b0fcd8ac1..015ac4fe4d1b6 100644 --- a/src/test/codegen/simd-wide-sum.rs +++ b/src/test/codegen/simd-wide-sum.rs @@ -47,8 +47,9 @@ pub fn wider_reduce_iter(x: Simd<u8, N>) -> u16 { #[no_mangle] // CHECK-LABEL: @wider_reduce_into_iter pub fn wider_reduce_into_iter(x: Simd<u8, N>) -> u16 { - // CHECK: zext <8 x i8> - // CHECK-SAME: to <8 x i16> - // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> + // FIXME MIR inlining messes up LLVM optimizations. + // WOULD-CHECK: zext <8 x i8> + // WOULD-CHECK-SAME: to <8 x i16> + // WOULD-CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> x.to_array().into_iter().map(u16::from).sum() } diff --git a/src/test/codegen/slice-ref-equality.rs b/src/test/codegen/slice-ref-equality.rs index e5cde5e9e7460..47fde12bf3036 100644 --- a/src/test/codegen/slice-ref-equality.rs +++ b/src/test/codegen/slice-ref-equality.rs @@ -1,4 +1,4 @@ -// compile-flags: -C opt-level=3 +// compile-flags: -C opt-level=3 -Zmerge-functions=disabled #![crate_type = "lib"] diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs index 2f375844cc716..03e2a2327fc4c 100644 --- a/src/test/codegen/swap-small-types.rs +++ b/src/test/codegen/swap-small-types.rs @@ -11,9 +11,10 @@ type RGB48 = [u16; 3]; // CHECK-LABEL: @swap_rgb48 #[no_mangle] pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { -// CHECK-NOT: alloca -// CHECK: load i48 -// CHECK: store i48 + // FIXME MIR inlining messes up LLVM optimizations. +// WOULD-CHECK-NOT: alloca +// WOULD-CHECK: load i48 +// WOULD-CHECK: store i48 swap(x, y) } diff --git a/src/test/codegen/vec-in-place.rs b/src/test/codegen/vec-in-place.rs index 13c41f7d4a906..62139aa9bebde 100644 --- a/src/test/codegen/vec-in-place.rs +++ b/src/test/codegen/vec-in-place.rs @@ -53,16 +53,18 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> { // CHECK-LABEL: @vec_iterator_cast_aggregate #[no_mangle] pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> { - // CHECK-NOT: loop - // CHECK-NOT: call + // FIXME These checks should be the same as other functions. + // CHECK-NOT: @__rust_alloc + // CHECK-NOT: @__rust_alloc vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect() } // CHECK-LABEL: @vec_iterator_cast_deaggregate #[no_mangle] pub fn vec_iterator_cast_deaggregate(vec: Vec<Bar>) -> Vec<[u64; 4]> { - // CHECK-NOT: loop - // CHECK-NOT: call + // FIXME These checks should be the same as other functions. + // CHECK-NOT: @__rust_alloc + // CHECK-NOT: @__rust_alloc // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4]. // This currently is not guaranteed for repr(Rust) types, but it happens to work here and diff --git a/src/test/debuginfo/basic-types-globals-lto.rs b/src/test/debuginfo/basic-types-globals-lto.rs new file mode 100644 index 0000000000000..555d51ced7118 --- /dev/null +++ b/src/test/debuginfo/basic-types-globals-lto.rs @@ -0,0 +1,81 @@ +// Caveat - gdb doesn't know about UTF-32 character encoding and will print a +// rust char as only its numerical value. + +// min-lldb-version: 310 +// min-gdb-version: 8.0 + +// no-prefer-dynamic +// compile-flags:-g -C lto +// gdb-command:run +// gdbg-command:print 'basic_types_globals::B' +// gdbr-command:print B +// gdb-check:$1 = false +// gdbg-command:print 'basic_types_globals::I' +// gdbr-command:print I +// gdb-check:$2 = -1 +// gdbg-command:print 'basic_types_globals::C' +// gdbr-command:print C +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 +// gdbg-command:print/d 'basic_types_globals::I8' +// gdbr-command:print I8 +// gdb-check:$4 = 68 +// gdbg-command:print 'basic_types_globals::I16' +// gdbr-command:print I16 +// gdb-check:$5 = -16 +// gdbg-command:print 'basic_types_globals::I32' +// gdbr-command:print I32 +// gdb-check:$6 = -32 +// gdbg-command:print 'basic_types_globals::I64' +// gdbr-command:print I64 +// gdb-check:$7 = -64 +// gdbg-command:print 'basic_types_globals::U' +// gdbr-command:print U +// gdb-check:$8 = 1 +// gdbg-command:print/d 'basic_types_globals::U8' +// gdbr-command:print U8 +// gdb-check:$9 = 100 +// gdbg-command:print 'basic_types_globals::U16' +// gdbr-command:print U16 +// gdb-check:$10 = 16 +// gdbg-command:print 'basic_types_globals::U32' +// gdbr-command:print U32 +// gdb-check:$11 = 32 +// gdbg-command:print 'basic_types_globals::U64' +// gdbr-command:print U64 +// gdb-check:$12 = 64 +// gdbg-command:print 'basic_types_globals::F32' +// gdbr-command:print F32 +// gdb-check:$13 = 2.5 +// gdbg-command:print 'basic_types_globals::F64' +// gdbr-command:print F64 +// gdb-check:$14 = 3.5 +// gdb-command:continue + +#![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] +#![omit_gdb_pretty_printer_section] + +// N.B. These are `mut` only so they don't constant fold away. +static mut B: bool = false; +static mut I: isize = -1; +static mut C: char = 'a'; +static mut I8: i8 = 68; +static mut I16: i16 = -16; +static mut I32: i32 = -32; +static mut I64: i64 = -64; +static mut U: usize = 1; +static mut U8: u8 = 100; +static mut U16: u16 = 16; +static mut U32: u32 = 32; +static mut U64: u64 = 64; +static mut F32: f32 = 2.5; +static mut F64: f64 = 3.5; + +fn main() { + _zzz(); // #break + + let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) }; +} + +fn _zzz() {()} diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs index 389b2cf015cac..a6d8c15bcdcf0 100644 --- a/src/test/debuginfo/basic-types-globals.rs +++ b/src/test/debuginfo/basic-types-globals.rs @@ -1,11 +1,8 @@ -// Caveats - gdb prints any 8-bit value (meaning rust I8 and u8 values) -// as its numerical value along with its associated ASCII char, there -// doesn't seem to be any way around this. Also, gdb doesn't know -// about UTF-32 character encoding and will print a rust char as only -// its numerical value. +// Caveat - gdb doesn't know about UTF-32 character encoding and will print a +// rust char as only its numerical value. // min-lldb-version: 310 -// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 +// min-gdb-version: 8.0 // compile-flags:-g // gdb-command:run @@ -18,7 +15,7 @@ // gdbg-command:print 'basic_types_globals::C' // gdbr-command:print C // gdbg-check:$3 = 97 -// gdbr-check:$3 = 97 'a' +// gdbr-check:$3 = 97 // gdbg-command:print/d 'basic_types_globals::I8' // gdbr-command:print I8 // gdb-check:$4 = 68 diff --git a/src/test/debuginfo/rwlock-read.rs b/src/test/debuginfo/rwlock-read.rs index e1c10a4d37fc3..ed9aae16b0db1 100644 --- a/src/test/debuginfo/rwlock-read.rs +++ b/src/test/debuginfo/rwlock-read.rs @@ -15,11 +15,8 @@ // // cdb-command:dx r // cdb-check:r [Type: std::sync::rwlock::RwLockReadGuard<i32>] -// cdb-check: [...] lock : [...] [Type: std::sync::rwlock::RwLock<i32> *] -// -// cdb-command:dx r.lock->data,d -// cdb-check:r.lock->data,d : 0 [Type: core::cell::UnsafeCell<i32>] -// cdb-check: [<Raw View>] [Type: core::cell::UnsafeCell<i32>] +// cdb-check: [...] data : NonNull([...]: 0) [Type: core::ptr::non_null::NonNull<i32>] +// cdb-check: [...] inner_lock : [...] [Type: std::sys_common::rwlock::MovableRwLock *] #[allow(unused_variables)] diff --git a/src/test/incremental/async-lifetimes.rs b/src/test/incremental/async-lifetimes.rs new file mode 100644 index 0000000000000..90a0b93b99a13 --- /dev/null +++ b/src/test/incremental/async-lifetimes.rs @@ -0,0 +1,19 @@ +// revisions: rpass1 rpass2 +// edition:2021 + +// See https://github.com/rust-lang/rust/issues/98890 + +#![allow(unused)] + +struct Foo; + +impl Foo { + async fn f(&self, _: &&()) -> &() { + &() + } +} + +#[cfg(rpass2)] +enum Bar {} + +fn main() {} diff --git a/src/test/incremental/issue-61323.rs b/src/test/incremental/issue-61323.rs index 448ce367b8c6b..97cbfe408f261 100644 --- a/src/test/incremental/issue-61323.rs +++ b/src/test/incremental/issue-61323.rs @@ -10,6 +10,6 @@ struct C(Box<A>); #[cfg(cfail)] struct C(A); -//[cfail]~^ ERROR 12:1: 12:13: recursive type `C` has infinite size [E0072] +//[cfail]~^ ERROR 12:1: 12:9: recursive type `C` has infinite size [E0072] fn main() {} diff --git a/src/test/incremental/split_debuginfo_cached.rs b/src/test/incremental/split_debuginfo_cached.rs new file mode 100644 index 0000000000000..25c802d5a1d2e --- /dev/null +++ b/src/test/incremental/split_debuginfo_cached.rs @@ -0,0 +1,25 @@ +// Check that compiling with packed Split DWARF twice succeeds. This should confirm that DWARF +// objects are cached as work products and available to the incremental compilation for `thorin` to +// pack into a DWARF package. + +// ignore-tidy-linelength +// only-x86_64-unknown-linux-gnu +// revisions:rpass1 rpass2 + +// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split +// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split + +#![feature(rustc_attrs)] +// For `rpass2`, nothing has changed so everything should re-used. +#![rustc_partition_reused(module = "split_debuginfo_cached", cfg = "rpass2")] +#![rustc_partition_reused(module = "split_debuginfo_cached-another_module", cfg = "rpass2")] + +mod another_module { + pub fn foo() -> &'static str { + "hello world" + } +} + +pub fn main() { + println!("{}", another_module::foo()); +} diff --git a/src/test/incremental/split_debuginfo_mode.rs b/src/test/incremental/split_debuginfo_mode.rs new file mode 100644 index 0000000000000..f2533e4146a84 --- /dev/null +++ b/src/test/incremental/split_debuginfo_mode.rs @@ -0,0 +1,33 @@ +// This test case makes sure that changing split-debuginfo commandline options triggers a full re-compilation. +// We only test on x86_64-unknown-linux-gnu because there all combinations split-debuginfo settings are valid +// and the test is platform-independent otherwise. + +// ignore-tidy-linelength +// only-x86_64-unknown-linux-gnu +// revisions:rpass1 rpass2 rpass3 rpass4 + +// [rpass1]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on +// [rpass2]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on +// [rpass3]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=on +// [rpass4]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=off + +#![feature(rustc_attrs)] +// For rpass2 we change -Csplit-debuginfo and thus expect every CGU to be recompiled +#![rustc_partition_codegened(module = "split_debuginfo_mode", cfg = "rpass2")] +#![rustc_partition_codegened(module = "split_debuginfo_mode-another_module", cfg = "rpass2")] +// For rpass3 we change -Zsplit-dwarf-kind and thus also expect every CGU to be recompiled +#![rustc_partition_codegened(module = "split_debuginfo_mode", cfg = "rpass3")] +#![rustc_partition_codegened(module = "split_debuginfo_mode-another_module", cfg = "rpass3")] +// For rpass4 we change -Zsplit-dwarf-inlining and thus also expect every CGU to be recompiled +#![rustc_partition_codegened(module = "split_debuginfo_mode", cfg = "rpass4")] +#![rustc_partition_codegened(module = "split_debuginfo_mode-another_module", cfg = "rpass4")] + +mod another_module { + pub fn foo() -> &'static str { + "hello world" + } +} + +pub fn main() { + println!("{}", another_module::foo()); +} diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir index deb5dbad7de67..c8848caa02709 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir @@ -39,7 +39,7 @@ fn main() -> () { _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 // mir::Constant // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 - // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir index deb5dbad7de67..c8848caa02709 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir @@ -39,7 +39,7 @@ fn main() -> () { _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27 // mir::Constant // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 - // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index 5b1ffc76fe5b3..9b35beccbcc5a 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -22,7 +22,7 @@ fn main() -> () { _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:13: 7:25 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { @@ -31,7 +31,7 @@ fn main() -> () { (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:17: 7:23 - // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> S {S::new}, val: Value(<ZST>) } } bb2: { @@ -47,7 +47,7 @@ fn main() -> () { _6 = std::mem::drop::<Box<S>>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 - // + literal: Const { ty: fn(Box<S>) {std::mem::drop::<Box<S>>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(Box<S>) {std::mem::drop::<Box<S>>}, val: Value(<ZST>) } } bb4: { diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff index fdc016a95d58e..7ecd67d7c679a 100644 --- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff +++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff @@ -4,98 +4,78 @@ fn <impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone(_1: &MyThing<T>) -> MyThing<T> { debug self => _1; // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 let mut _0: MyThing<T>; // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 - let _2: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - let _3: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - let _4: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - let mut _5: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - let mut _6: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - let _7: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - let mut _8: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - let mut _9: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - let _10: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - let mut _11: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - let mut _12: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - let _13: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - scope 1 { - debug __self_0_0 => _2; // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - debug __self_0_1 => _3; // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - debug __self_0_2 => _4; // in scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - } + let mut _2: T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let mut _3: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let _4: &T; // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + let mut _5: u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let mut _6: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let _7: &u64; // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + let mut _8: [f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let mut _9: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + let _10: &[f32; 3]; // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 bb0: { StorageLive(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - _2 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - StorageLive(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - _3 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - StorageLive(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - _4 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - StorageLive(_5); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - StorageLive(_6); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - StorageLive(_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 -- _7 = &(*_2); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 -- _6 = &(*_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 -+ _7 = _2; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 -+ _6 = _7; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - _5 = <T as Clone>::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + StorageLive(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + StorageLive(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + _4 = &((*_1).0: T); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 +- _3 = &(*_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 ++ _3 = _4; // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 + _2 = <T as Clone>::clone(move _3) -> bb1; // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9 // mir::Constant // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9 - // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(<ZST>) } } bb1: { - StorageDead(_6); // scope 1 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9 - StorageLive(_8); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - StorageLive(_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - StorageLive(_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -- _10 = &(*_3); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -- _9 = &(*_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -- _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + StorageDead(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9 + StorageLive(_5); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + StorageLive(_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + StorageLive(_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 + _7 = &((*_1).1: u64); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- _6 = &(*_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- _5 = <u64 as Clone>::clone(move _6) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 - // mir::Constant - // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -- // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(Scalar(<ZST>)) } -+ _10 = _3; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -+ _9 = _10; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -+ _8 = (*_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 -+ goto -> bb2; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 +- // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(<ZST>) } ++ _6 = _7; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ _5 = (*_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 ++ goto -> bb2; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11 } bb2: { - StorageDead(_9); // scope 1 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11 - StorageLive(_11); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - StorageLive(_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - StorageLive(_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -- _13 = &(*_4); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -- _12 = &(*_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -- _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + StorageDead(_6); // scope 0 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11 + StorageLive(_8); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + StorageLive(_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + StorageLive(_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 + _10 = &((*_1).2: [f32; 3]); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _9 = &(*_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- _8 = <[f32; 3] as Clone>::clone(move _9) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 - // mir::Constant - // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -- // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar(<ZST>)) } -+ _13 = _4; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -+ _12 = _13; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -+ _11 = (*_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 -+ goto -> bb3; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 +- // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(<ZST>) } ++ _9 = _10; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ _8 = (*_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 ++ goto -> bb3; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16 } bb3: { - StorageDead(_12); // scope 1 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16 - Deinit(_0); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 - (_0.0: T) = move _5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 - (_0.1: u64) = move _8; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 - (_0.2: [f32; 3]) = move _11; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 - StorageDead(_13); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_11); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_10); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_8); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_7); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_5); // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 - StorageDead(_3); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_9); // scope 0 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16 + Deinit(_0); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.0: T) = move _2; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.1: u64) = move _5; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + (_0.2: [f32; 3]) = move _8; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15 + StorageDead(_8); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_5); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 StorageDead(_2); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_10); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_7); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 return; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15 } bb4 (cleanup): { - drop(_5) -> bb5; // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 + drop(_2) -> bb5; // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15 } bb5 (cleanup): { diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 816c598059dd5..bc82222d11856 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -33,18 +33,18 @@ _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42 - // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) } } bb1: { - StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 - StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:28 } bb2 (cleanup): { - resume; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45 + resume; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:28 } - } - diff --git a/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir b/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir index 4d24387afc761..2e63c2c25fac3 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir +++ b/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir @@ -12,6 +12,6 @@ static BOP: &i32 = { _1 = &_2; // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 _0 = &(*_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:22: 16:23 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:16:1: 16:24 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:16:1: 16:17 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 096b427bb758b..39dcf2f10c6f2 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -35,18 +35,18 @@ _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53 - // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) } } bb1: { - StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 - StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:28 } bb2 (cleanup): { - resume; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56 + resume; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:28 } } - diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index 87302424914d9..919b909435197 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -32,7 +32,7 @@ + _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 // mir::Constant // + span: $DIR/boxes.rs:12:14: 12:22 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index 84d72202d527e..852a2419f558d 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -30,7 +30,7 @@ _4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9 - // + literal: Const { ty: fn(usize) {read}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(usize) {read}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index d7636c817099a..d0287cc2b2b64 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -19,7 +19,7 @@ _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 - // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/std/src/panic.rs:LL:COL // + literal: Const { ty: &str, val: Value(Slice(..)) } diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff index e874adebbe01b..5991d7637f50f 100644 --- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff @@ -20,7 +20,7 @@ _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:16:5: 16:23 // mir::Constant // + span: $DIR/issue-66971.rs:16:5: 16:11 - // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 69d31b681b4e5..149a60c0bbb54 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -21,7 +21,7 @@ _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:11:5: 11:20 // mir::Constant // + span: $DIR/issue-67019.rs:11:5: 11:9 - // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff index 86fac1270d0fc..724cf096f5946 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff @@ -17,7 +17,7 @@ _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:34 // mir::Constant // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32 - // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 247d8f32432c0..a22efa7eaf50a 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -26,7 +26,7 @@ _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:13: 5:18 // mir::Constant // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16 - // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> i32 {foo}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 037febdf3a579..80f461a4c02cf 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -16,7 +16,7 @@ _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17 // mir::Constant // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17 - // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {main}, val: Value(<ZST>) } _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26 _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff index af48ff0b098e7..6343ee80a2562 100644 --- a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff @@ -21,7 +21,7 @@ + _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 - // + literal: Const { ty: fn(u32) {consume}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(u32) {consume}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff index f031a703a9d72..5dfa05a46d377 100644 --- a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff @@ -16,14 +16,14 @@ _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 // mir::Constant // + span: $DIR/switch_int.rs:9:14: 9:17 - // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) } } bb2: { _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 // mir::Constant // + span: $DIR/switch_int.rs:8:14: 8:17 - // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff index f2b02551146eb..704b4bbe018d5 100644 --- a/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff +++ b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff @@ -16,14 +16,14 @@ _0 = foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21 // mir::Constant // + span: $DIR/switch_int.rs:9:14: 9:17 - // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) } } bb2: { _0 = foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20 // mir::Constant // + span: $DIR/switch_int.rs:8:14: 8:17 - // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff index 2bcd10f160b82..adb182314ac5e 100644 --- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff @@ -22,7 +22,7 @@ _2 = consume(move _3) -> bb1; // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15 // mir::Constant // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12 - // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff index 6037f89086dc1..5f8019ac975a3 100644 --- a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff @@ -28,7 +28,7 @@ _5 = cond() -> bb2; // scope 0 at $DIR/cycle.rs:12:11: 12:17 // mir::Constant // + span: $DIR/cycle.rs:12:11: 12:15 - // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff index 372b14eb7c92a..688015f68d37e 100644 --- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff +++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff @@ -27,7 +27,7 @@ + _2 = transmute::<&str, &[u8]>(move _8) -> bb12; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/str/mod.rs:LL:COL - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff index f5eabf8696796..9affe5a50061d 100644 --- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff +++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff @@ -2,110 +2,110 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_complex_case.rs:3:11: 3:11 - let mut _1: std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let mut _2: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let _3: [i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:4:18: 4:26 - let mut _4: std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let mut _5: (); // in scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2 - let _6: (); // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let mut _7: std::option::Option<&i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let mut _8: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let mut _9: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let mut _10: isize; // in scope 0 at $DIR/derefer_complex_case.rs:4:5: 4:40 - let mut _11: !; // in scope 0 at $DIR/derefer_complex_case.rs:4:5: 4:40 - let mut _13: i32; // in scope 0 at $DIR/derefer_complex_case.rs:4:34: 4:37 - let mut _14: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 -+ let mut _15: &i32; // in scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 + let mut _0: (); // return place in scope 0 at $DIR/derefer_complex_case.rs:4:11: 4:11 + let mut _1: std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _2: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let _3: [i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:5:18: 5:26 + let mut _4: std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _5: (); // in scope 0 at $DIR/derefer_complex_case.rs:4:1: 6:2 + let _6: (); // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _7: std::option::Option<&i32>; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _8: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _9: &mut std::slice::Iter<i32>; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let mut _10: isize; // in scope 0 at $DIR/derefer_complex_case.rs:5:5: 5:40 + let mut _11: !; // in scope 0 at $DIR/derefer_complex_case.rs:5:5: 5:40 + let mut _13: i32; // in scope 0 at $DIR/derefer_complex_case.rs:5:34: 5:37 + let mut _14: &[i32; 2]; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 ++ let mut _15: &i32; // in scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 scope 1 { - debug iter => _4; // in scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - let _12: i32; // in scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13 + debug iter => _4; // in scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + let _12: i32; // in scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 scope 2 { - debug foo => _12; // in scope 2 at $DIR/derefer_complex_case.rs:4:10: 4:13 + debug foo => _12; // in scope 2 at $DIR/derefer_complex_case.rs:5:10: 5:13 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - _14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 + StorageLive(_1); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:4:17: 4:26 + // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) } - _2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 + _2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:4:17: 4:26 - // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(Scalar(<ZST>)) } + // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 + // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(<ZST>) } } bb1: { - StorageDead(_2); // scope 0 at $DIR/derefer_complex_case.rs:4:25: 4:26 - StorageLive(_4); // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - _4 = move _1; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26 - goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40 + StorageDead(_2); // scope 0 at $DIR/derefer_complex_case.rs:5:25: 5:26 + StorageLive(_4); // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _4 = move _1; // scope 0 at $DIR/derefer_complex_case.rs:5:17: 5:26 + goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 } bb2: { - StorageLive(_6); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - StorageLive(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - StorageLive(_8); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - StorageLive(_9); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - _9 = &mut _4; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - _8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 + StorageLive(_6); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_8); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + StorageLive(_9); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _9 = &mut _4; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:4:17: 4:26 - // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(Scalar(<ZST>)) } + // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 + // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(<ZST>) } } bb3: { - StorageDead(_8); // scope 1 at $DIR/derefer_complex_case.rs:4:25: 4:26 - _10 = discriminant(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 - switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 + StorageDead(_8); // scope 1 at $DIR/derefer_complex_case.rs:5:25: 5:26 + _10 = discriminant(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 + switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 } bb4: { - StorageLive(_12); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13 -- _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13 -+ StorageLive(_15); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13 -+ _15 = move ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13 -+ _12 = (*_15); // scope 1 at $DIR/derefer_complex_case.rs:4:10: 4:13 -+ StorageDead(_15); // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37 - StorageLive(_13); // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37 - _13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:4:34: 4:37 - _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:4:29: 4:38 + StorageLive(_12); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 +- _12 = (*((_7 as Some).0: &i32)); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ StorageLive(_15); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ _15 = deref_copy ((_7 as Some).0: &i32); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ _12 = (*_15); // scope 1 at $DIR/derefer_complex_case.rs:5:10: 5:13 ++ StorageDead(_15); // scope 2 at $DIR/derefer_complex_case.rs:5:34: 5:37 + StorageLive(_13); // scope 2 at $DIR/derefer_complex_case.rs:5:34: 5:37 + _13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:5:34: 5:37 + _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:5:29: 5:38 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:4:29: 4:33 - // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(Scalar(<ZST>)) } + // + span: $DIR/derefer_complex_case.rs:5:29: 5:33 + // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) } } bb5: { - unreachable; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26 + unreachable; // scope 1 at $DIR/derefer_complex_case.rs:5:17: 5:26 } bb6: { - _0 = const (); // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40 - StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_4); // scope 0 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_1); // scope 0 at $DIR/derefer_complex_case.rs:4:39: 4:40 - return; // scope 0 at $DIR/derefer_complex_case.rs:5:2: 5:2 + _0 = const (); // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 + StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_4); // scope 0 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_1); // scope 0 at $DIR/derefer_complex_case.rs:5:39: 5:40 + return; // scope 0 at $DIR/derefer_complex_case.rs:6:2: 6:2 } bb7: { - StorageDead(_13); // scope 2 at $DIR/derefer_complex_case.rs:4:37: 4:38 - StorageDead(_12); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40 - _5 = const (); // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40 - goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40 - } - - bb8 (cleanup): { - resume; // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2 + StorageDead(_13); // scope 2 at $DIR/derefer_complex_case.rs:5:37: 5:38 + StorageDead(_12); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_9); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_7); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:5:39: 5:40 + _5 = const (); // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 + goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:5:5: 5:40 ++ } ++ ++ bb8 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_complex_case.rs:4:1: 6:2 } } diff --git a/src/test/mir-opt/derefer_complex_case.rs b/src/test/mir-opt/derefer_complex_case.rs index 6abf49f9966ce..48bec39074c89 100644 --- a/src/test/mir-opt/derefer_complex_case.rs +++ b/src/test/mir-opt/derefer_complex_case.rs @@ -1,4 +1,5 @@ // EMIT_MIR derefer_complex_case.main.Derefer.diff +// ignore-wasm32 fn main() { for &foo in &[42, 43] { drop(foo) } diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff index e131adae2b683..fe64156f42f84 100644 --- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff @@ -8,7 +8,6 @@ let mut _3: usize; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 let mut _4: *mut u8; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 let mut _5: std::boxed::Box<std::boxed::Box<u32>>; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 - let mut _6: (); // in scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 scope 1 { } @@ -19,26 +18,26 @@ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:10:5: 10:12 // mir::Constant // + span: $DIR/derefer_inline_test.rs:10:5: 10:12 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { StorageLive(_5); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 _5 = ShallowInitBox(move _4, std::boxed::Box<u32>); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 - (*_5) = f() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12 + (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12 // mir::Constant // + span: $DIR/derefer_inline_test.rs:10:9: 10:10 - // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(<ZST>) } } bb2: { _1 = move _5; // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 - goto -> bb3; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + drop(_5) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 } bb3: { StorageDead(_5); // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 - drop(_1) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 + drop(_1) -> bb4; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 } bb4: { @@ -48,22 +47,15 @@ } bb5 (cleanup): { - goto -> bb8; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + drop(_1) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 } bb6 (cleanup): { - resume; // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2 + drop(_5) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 } bb7 (cleanup): { - _6 = alloc::alloc::box_free::<Box<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::boxed::Box<u32>>), move (_5.1: std::alloc::Global)) -> bb6; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 - // mir::Constant - // + span: $DIR/derefer_inline_test.rs:10:11: 10:12 - // + literal: Const { ty: unsafe fn(Unique<Box<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Box<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) } - } - - bb8 (cleanup): { - goto -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + resume; // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2 } } diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff index 8b91a65bf3d7d..003803fbd5ca9 100644 --- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff @@ -2,102 +2,102 @@ + // MIR for `main` after Derefer fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/derefer_terminator_test.rs:2:11: 2:11 - let _1: bool; // in scope 0 at $DIR/derefer_terminator_test.rs:3:9: 3:10 - let _3: (); // in scope 0 at $DIR/derefer_terminator_test.rs:5:5: 8:6 - let mut _4: &&&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22 - let _5: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:17: 5:21 - let _6: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:18: 5:21 - let _7: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:19: 5:21 -+ let mut _10: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22 -+ let mut _11: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22 -+ let mut _12: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:15: 5:22 + let mut _0: (); // return place in scope 0 at $DIR/derefer_terminator_test.rs:4:11: 4:11 + let _1: bool; // in scope 0 at $DIR/derefer_terminator_test.rs:5:9: 5:10 + let _3: (); // in scope 0 at $DIR/derefer_terminator_test.rs:7:5: 10:6 + let mut _4: &&&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 + let _5: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:17: 7:21 + let _6: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:18: 7:21 + let _7: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:19: 7:21 ++ let mut _10: &&&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 ++ let mut _11: &&bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 ++ let mut _12: &bool; // in scope 0 at $DIR/derefer_terminator_test.rs:7:15: 7:22 scope 1 { - debug b => _1; // in scope 1 at $DIR/derefer_terminator_test.rs:3:9: 3:10 - let _2: bool; // in scope 1 at $DIR/derefer_terminator_test.rs:4:9: 4:10 + debug b => _1; // in scope 1 at $DIR/derefer_terminator_test.rs:5:9: 5:10 + let _2: bool; // in scope 1 at $DIR/derefer_terminator_test.rs:6:9: 6:10 scope 2 { - debug d => _2; // in scope 2 at $DIR/derefer_terminator_test.rs:4:9: 4:10 - let _8: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:6:22: 6:23 - let _9: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:9:9: 9:10 + debug d => _2; // in scope 2 at $DIR/derefer_terminator_test.rs:6:9: 6:10 + let _8: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:8:22: 8:23 + let _9: i32; // in scope 2 at $DIR/derefer_terminator_test.rs:11:9: 11:10 scope 3 { - debug x => _8; // in scope 3 at $DIR/derefer_terminator_test.rs:6:22: 6:23 + debug x => _8; // in scope 3 at $DIR/derefer_terminator_test.rs:8:22: 8:23 } scope 4 { - debug y => _9; // in scope 4 at $DIR/derefer_terminator_test.rs:9:9: 9:10 + debug y => _9; // in scope 4 at $DIR/derefer_terminator_test.rs:11:9: 11:10 } } } bb0: { - StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:3:9: 3:10 - _1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:3:13: 3:18 + StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:5:9: 5:10 + _1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:5:13: 5:18 // mir::Constant - // + span: $DIR/derefer_terminator_test.rs:3:13: 3:16 - // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) } + // + span: $DIR/derefer_terminator_test.rs:5:13: 5:16 + // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) } } bb1: { - StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:4:9: 4:10 - _2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:4:13: 4:18 + StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:6:9: 6:10 + _2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:6:13: 6:18 // mir::Constant - // + span: $DIR/derefer_terminator_test.rs:4:13: 4:16 - // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) } + // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16 + // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) } } bb2: { - StorageLive(_3); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 8:6 - StorageLive(_4); // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22 - StorageLive(_5); // scope 2 at $DIR/derefer_terminator_test.rs:5:17: 5:21 - StorageLive(_6); // scope 2 at $DIR/derefer_terminator_test.rs:5:18: 5:21 - StorageLive(_7); // scope 2 at $DIR/derefer_terminator_test.rs:5:19: 5:21 - _7 = &_1; // scope 2 at $DIR/derefer_terminator_test.rs:5:19: 5:21 - _6 = &_7; // scope 2 at $DIR/derefer_terminator_test.rs:5:18: 5:21 - _5 = &_6; // scope 2 at $DIR/derefer_terminator_test.rs:5:17: 5:21 - _4 = &_5; // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22 -- switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ StorageLive(_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ _10 = move (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ StorageLive(_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ _11 = move (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ StorageDead(_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ StorageLive(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ _12 = move (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ StorageDead(_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + StorageLive(_3); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 10:6 + StorageLive(_4); // scope 2 at $DIR/derefer_terminator_test.rs:7:15: 7:22 + StorageLive(_5); // scope 2 at $DIR/derefer_terminator_test.rs:7:17: 7:21 + StorageLive(_6); // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:21 + StorageLive(_7); // scope 2 at $DIR/derefer_terminator_test.rs:7:19: 7:21 + _7 = &_1; // scope 2 at $DIR/derefer_terminator_test.rs:7:19: 7:21 + _6 = &_7; // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:21 + _5 = &_6; // scope 2 at $DIR/derefer_terminator_test.rs:7:17: 7:21 + _4 = &_5; // scope 2 at $DIR/derefer_terminator_test.rs:7:15: 7:22 +- switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageLive(_10); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ _10 = deref_copy (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageLive(_11); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ _11 = deref_copy (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageDead(_10); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageLive(_12); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ _12 = deref_copy (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ StorageDead(_11); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 ++ switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 } bb3: { -+ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 - _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:20 - goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:7:18: 7:20 ++ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 + _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:9:18: 9:20 + goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:9:18: 9:20 } bb4: { -+ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 - StorageLive(_8); // scope 2 at $DIR/derefer_terminator_test.rs:6:22: 6:23 - _8 = const 5_i32; // scope 2 at $DIR/derefer_terminator_test.rs:6:26: 6:27 - _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:6:17: 6:29 - StorageDead(_8); // scope 2 at $DIR/derefer_terminator_test.rs:6:28: 6:29 - goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:6:28: 6:29 ++ StorageDead(_12); // scope 2 at $DIR/derefer_terminator_test.rs:7:5: 7:22 + StorageLive(_8); // scope 2 at $DIR/derefer_terminator_test.rs:8:22: 8:23 + _8 = const 5_i32; // scope 2 at $DIR/derefer_terminator_test.rs:8:26: 8:27 + _3 = const (); // scope 2 at $DIR/derefer_terminator_test.rs:8:17: 8:29 + StorageDead(_8); // scope 2 at $DIR/derefer_terminator_test.rs:8:28: 8:29 + goto -> bb5; // scope 2 at $DIR/derefer_terminator_test.rs:8:28: 8:29 } bb5: { - StorageDead(_7); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6 - StorageDead(_6); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6 - StorageDead(_5); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6 - StorageDead(_4); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6 - StorageDead(_3); // scope 2 at $DIR/derefer_terminator_test.rs:8:5: 8:6 - StorageLive(_9); // scope 2 at $DIR/derefer_terminator_test.rs:9:9: 9:10 - _9 = const 42_i32; // scope 2 at $DIR/derefer_terminator_test.rs:9:13: 9:15 - _0 = const (); // scope 0 at $DIR/derefer_terminator_test.rs:2:11: 10:2 - StorageDead(_9); // scope 2 at $DIR/derefer_terminator_test.rs:10:1: 10:2 - StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:10:1: 10:2 - StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:10:1: 10:2 - return; // scope 0 at $DIR/derefer_terminator_test.rs:10:2: 10:2 - } - - bb6 (cleanup): { - resume; // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2 + StorageDead(_7); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_6); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_5); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_4); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageDead(_3); // scope 2 at $DIR/derefer_terminator_test.rs:10:5: 10:6 + StorageLive(_9); // scope 2 at $DIR/derefer_terminator_test.rs:11:9: 11:10 + _9 = const 42_i32; // scope 2 at $DIR/derefer_terminator_test.rs:11:13: 11:15 + _0 = const (); // scope 0 at $DIR/derefer_terminator_test.rs:4:11: 12:2 + StorageDead(_9); // scope 2 at $DIR/derefer_terminator_test.rs:12:1: 12:2 + StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:12:1: 12:2 + StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:12:1: 12:2 + return; // scope 0 at $DIR/derefer_terminator_test.rs:12:2: 12:2 ++ } ++ ++ bb6 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_terminator_test.rs:4:1: 12:2 } } diff --git a/src/test/mir-opt/derefer_terminator_test.rs b/src/test/mir-opt/derefer_terminator_test.rs index 11f5b20636d54..787b14ae735d5 100644 --- a/src/test/mir-opt/derefer_terminator_test.rs +++ b/src/test/mir-opt/derefer_terminator_test.rs @@ -1,4 +1,6 @@ // EMIT_MIR derefer_terminator_test.main.Derefer.diff +// ignore-wasm32 + fn main() { let b = foo(); let d = foo(); diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff index 84476aeed7a6c..df76b3ebc2deb 100644 --- a/src/test/mir-opt/derefer_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_test.main.Derefer.diff @@ -34,13 +34,13 @@ StorageLive(_4); // scope 2 at $DIR/derefer_test.rs:5:9: 5:10 - _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 + StorageLive(_6); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 -+ _6 = move (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ _6 = deref_copy (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 + _4 = &mut ((*_6).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 + StorageDead(_6); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 StorageLive(_5); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 - _5 = &mut ((*(_2.1: &mut (i32, i32))).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 + StorageLive(_7); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 -+ _7 = move (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ _7 = deref_copy (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 + _5 = &mut ((*_7).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 + StorageDead(_7); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 _0 = const (); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 @@ -49,10 +49,10 @@ StorageDead(_2); // scope 1 at $DIR/derefer_test.rs:7:1: 7:2 StorageDead(_1); // scope 0 at $DIR/derefer_test.rs:7:1: 7:2 return; // scope 0 at $DIR/derefer_test.rs:7:2: 7:2 - } - - bb1 (cleanup): { - resume; // scope 0 at $DIR/derefer_test.rs:2:1: 7:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test.rs:2:1: 7:2 } } diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff index b8e5a0c328f4d..044c92a2f4325 100644 --- a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff +++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff @@ -58,24 +58,24 @@ StorageLive(_8); // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 - _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageLive(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 -+ _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _10 = deref_copy (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 -+ _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _11 = deref_copy ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageDead(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 -+ _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _12 = deref_copy ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageDead(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 - _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageLive(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 -+ _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _13 = deref_copy (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 -+ _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _14 = deref_copy ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageDead(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 -+ _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _15 = deref_copy ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageDead(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 @@ -87,10 +87,10 @@ StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2 return; // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2 - } - - bb1 (cleanup): { - resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 } } diff --git a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff index c3aa19e6c5f84..97fb7fce14e40 100644 --- a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff @@ -19,7 +19,7 @@ _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 // mir::Constant // + span: $DIR/branch.rs:13:13: 13:16 - // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) } } bb1: { @@ -28,7 +28,7 @@ _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 // mir::Constant // + span: $DIR/branch.rs:15:16: 15:20 - // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) } } bb2: { @@ -45,7 +45,7 @@ _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 // mir::Constant // + span: $DIR/branch.rs:18:9: 18:12 - // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) } } bb5: { diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff index 3f9ba4ad4f0ac..11a0d1f609f72 100644 --- a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff @@ -14,7 +14,7 @@ _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10 - // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff index 963881d7ae062..1346a04938a20 100644 --- a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff @@ -14,7 +14,7 @@ _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 - // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff index 8e44d68d9348e..516180fbec68d 100644 --- a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -27,7 +27,7 @@ _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 // mir::Constant // + span: $DIR/cycle.rs:9:17: 9:20 - // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff index 582a1738cbf96..acfd3c18fc930 100644 --- a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -22,7 +22,7 @@ _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 // mir::Constant // + span: $DIR/union.rs:13:23: 13:26 - // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> u32 {val}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff index 67ce0c2aabb1c..988694000ee99 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff @@ -93,7 +93,7 @@ - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -101,7 +101,7 @@ bb1: { StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -123,7 +123,7 @@ bb3: { StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -131,7 +131,7 @@ bb4: { StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -139,7 +139,7 @@ bb5: { StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -149,14 +149,14 @@ - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 @@ -195,14 +195,14 @@ - StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 - _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 - _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 @@ -241,14 +241,14 @@ - StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 - _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 - _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 @@ -287,14 +287,14 @@ - StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 - _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 - _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index c2b00f915a4eb..1b090a33ffcd7 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -79,7 +79,7 @@ StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -87,7 +87,7 @@ bb1: { StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -107,7 +107,7 @@ bb3: { StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -115,7 +115,7 @@ bb4: { StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -123,7 +123,7 @@ bb5: { StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -132,12 +132,12 @@ bb6: { StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 @@ -160,12 +160,12 @@ bb7: { StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 - _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 @@ -188,12 +188,12 @@ bb8: { StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 - _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 @@ -216,12 +216,12 @@ bb9: { StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 - _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff index 982dd7a27bc6b..2ee7374250217 100644 --- a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff @@ -17,7 +17,7 @@ bb1: { StorageLive(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - _4 = move (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + _4 = deref_copy (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 _2 = discriminant((*_4)); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 StorageDead(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 diff --git a/src/test/mir-opt/enum_cast.bar.mir_map.0.mir b/src/test/mir-opt/enum_cast.bar.mir_map.0.mir new file mode 100644 index 0000000000000..1b4a469135cb6 --- /dev/null +++ b/src/test/mir-opt/enum_cast.bar.mir_map.0.mir @@ -0,0 +1,13 @@ +// MIR for `bar` 0 mir_map + +fn bar(_1: Bar) -> usize { + debug bar => _1; // in scope 0 at $DIR/enum_cast.rs:22:8: 22:11 + let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:22:21: 22:26 + let mut _2: isize; // in scope 0 at $DIR/enum_cast.rs:23:5: 23:8 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:23:5: 23:17 + _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:23:5: 23:17 + return; // scope 0 at $DIR/enum_cast.rs:24:2: 24:2 + } +} diff --git a/src/test/mir-opt/enum_cast.boo.mir_map.0.mir b/src/test/mir-opt/enum_cast.boo.mir_map.0.mir new file mode 100644 index 0000000000000..7724e89a22854 --- /dev/null +++ b/src/test/mir-opt/enum_cast.boo.mir_map.0.mir @@ -0,0 +1,13 @@ +// MIR for `boo` 0 mir_map + +fn boo(_1: Boo) -> usize { + debug boo => _1; // in scope 0 at $DIR/enum_cast.rs:26:8: 26:11 + let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:26:21: 26:26 + let mut _2: u8; // in scope 0 at $DIR/enum_cast.rs:27:5: 27:8 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:27:5: 27:17 + _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:27:5: 27:17 + return; // scope 0 at $DIR/enum_cast.rs:28:2: 28:2 + } +} diff --git a/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir b/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir new file mode 100644 index 0000000000000..a9dcfadae75c7 --- /dev/null +++ b/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir @@ -0,0 +1,54 @@ +// MIR for `droppy` 0 mir_map + +fn droppy() -> () { + let mut _0: (); // return place in scope 0 at $DIR/enum_cast.rs:39:13: 39:13 + let _1: (); // in scope 0 at $DIR/enum_cast.rs:40:5: 45:6 + let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:41:13: 41:14 + let mut _4: isize; // in scope 0 at $DIR/enum_cast.rs:44:17: 44:18 + let _5: Droppy; // in scope 0 at $DIR/enum_cast.rs:46:9: 46:10 + scope 1 { + debug x => _2; // in scope 1 at $DIR/enum_cast.rs:41:13: 41:14 + scope 2 { + debug y => _3; // in scope 2 at $DIR/enum_cast.rs:44:13: 44:14 + } + scope 3 { + let _3: usize; // in scope 3 at $DIR/enum_cast.rs:44:13: 44:14 + } + } + scope 4 { + debug z => _5; // in scope 4 at $DIR/enum_cast.rs:46:9: 46:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/enum_cast.rs:40:5: 45:6 + StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:41:13: 41:14 + _2 = Droppy::C; // scope 0 at $DIR/enum_cast.rs:41:17: 41:26 + FakeRead(ForLet(None), _2); // scope 0 at $DIR/enum_cast.rs:41:13: 41:14 + StorageLive(_3); // scope 3 at $DIR/enum_cast.rs:44:13: 44:14 + _4 = discriminant(_2); // scope 3 at $DIR/enum_cast.rs:44:17: 44:27 + _3 = move _4 as usize (Misc); // scope 3 at $DIR/enum_cast.rs:44:17: 44:27 + FakeRead(ForLet(None), _3); // scope 3 at $DIR/enum_cast.rs:44:13: 44:14 + _1 = const (); // scope 0 at $DIR/enum_cast.rs:40:5: 45:6 + StorageDead(_3); // scope 1 at $DIR/enum_cast.rs:45:5: 45:6 + drop(_2) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:45:5: 45:6 + } + + bb1: { + StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:45:5: 45:6 + StorageDead(_1); // scope 0 at $DIR/enum_cast.rs:45:5: 45:6 + StorageLive(_5); // scope 0 at $DIR/enum_cast.rs:46:9: 46:10 + _5 = Droppy::B; // scope 0 at $DIR/enum_cast.rs:46:13: 46:22 + FakeRead(ForLet(None), _5); // scope 0 at $DIR/enum_cast.rs:46:9: 46:10 + _0 = const (); // scope 0 at $DIR/enum_cast.rs:39:13: 47:2 + drop(_5) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:47:1: 47:2 + } + + bb2: { + StorageDead(_5); // scope 0 at $DIR/enum_cast.rs:47:1: 47:2 + return; // scope 0 at $DIR/enum_cast.rs:47:2: 47:2 + } + + bb3 (cleanup): { + resume; // scope 0 at $DIR/enum_cast.rs:39:1: 47:2 + } +} diff --git a/src/test/mir-opt/enum_cast.foo.mir_map.0.mir b/src/test/mir-opt/enum_cast.foo.mir_map.0.mir new file mode 100644 index 0000000000000..d89dc9519239b --- /dev/null +++ b/src/test/mir-opt/enum_cast.foo.mir_map.0.mir @@ -0,0 +1,13 @@ +// MIR for `foo` 0 mir_map + +fn foo(_1: Foo) -> usize { + debug foo => _1; // in scope 0 at $DIR/enum_cast.rs:18:8: 18:11 + let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:18:21: 18:26 + let mut _2: isize; // in scope 0 at $DIR/enum_cast.rs:19:5: 19:8 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/enum_cast.rs:19:5: 19:17 + _0 = move _2 as usize (Misc); // scope 0 at $DIR/enum_cast.rs:19:5: 19:17 + return; // scope 0 at $DIR/enum_cast.rs:20:2: 20:2 + } +} diff --git a/src/test/mir-opt/enum_cast.rs b/src/test/mir-opt/enum_cast.rs new file mode 100644 index 0000000000000..090142aaf3559 --- /dev/null +++ b/src/test/mir-opt/enum_cast.rs @@ -0,0 +1,50 @@ +// EMIT_MIR enum_cast.foo.mir_map.0.mir +// EMIT_MIR enum_cast.bar.mir_map.0.mir +// EMIT_MIR enum_cast.boo.mir_map.0.mir + +enum Foo { + A +} + +enum Bar { + A, B +} + +#[repr(u8)] +enum Boo { + A, B +} + +fn foo(foo: Foo) -> usize { + foo as usize +} + +fn bar(bar: Bar) -> usize { + bar as usize +} + +fn boo(boo: Boo) -> usize { + boo as usize +} + +// EMIT_MIR enum_cast.droppy.mir_map.0.mir +enum Droppy { + A, B, C +} + +impl Drop for Droppy { + fn drop(&mut self) {} +} + +fn droppy() { + { + let x = Droppy::C; + // remove this entire test once `cenum_impl_drop_cast` becomes a hard error + #[allow(cenum_impl_drop_cast)] + let y = x as usize; + } + let z = Droppy::B; +} + +fn main() { +} diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index 15409fa0dd23c..a930d83b9e798 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -41,7 +41,7 @@ _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 // mir::Constant // + span: $DIR/funky_arms.rs:15:26: 15:35 - // + literal: Const { ty: for<'r> fn(&'r Formatter) -> bool {Formatter::sign_plus}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r Formatter) -> bool {Formatter::sign_plus}, val: Value(<ZST>) } } bb1: { @@ -69,7 +69,7 @@ _7 = Formatter::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:24:30: 24:45 // mir::Constant // + span: $DIR/funky_arms.rs:24:34: 24:43 - // + literal: Const { ty: for<'r> fn(&'r Formatter) -> Option<usize> {Formatter::precision}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r Formatter) -> Option<usize> {Formatter::precision}, val: Value(<ZST>) } } bb5: { @@ -100,7 +100,7 @@ _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87 // mir::Constant // + span: $DIR/funky_arms.rs:26:9: 26:42 - // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) } } bb7: { @@ -125,7 +125,7 @@ _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68 // mir::Constant // + span: $DIR/funky_arms.rs:28:9: 28:45 - // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) } } bb9: { diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index 84ccf25ef750e..c78c345dec224 100644 --- a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir +++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -14,22 +14,22 @@ }, } */ -fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6]) -> () { - let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 - let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 +fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 10:17]) -> () { + let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 let _4: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14 let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14 let mut _6: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18 - let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 - let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 scope 1 { debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 } bb0: { - _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 - switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb1: { @@ -44,11 +44,11 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1 } bb3: { - return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb4 (cleanup): { - resume; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + resume; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb5 (cleanup): { @@ -57,11 +57,11 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1 } bb6: { - return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb7: { - goto -> bb9; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + goto -> bb9; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb8: { @@ -69,16 +69,16 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1 } bb9: { - goto -> bb6; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + goto -> bb6; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb10: { - StorageLive(_4); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 - StorageLive(_5); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 - goto -> bb1; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + StorageLive(_4); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + StorageLive(_5); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 + goto -> bb1; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } bb11: { - return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + return; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17 } } diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir index 739492d7d249f..af4ed32c50889 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` before StateTransform -fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6], _2: ()) -> () +fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 22:18], _2: ()) -> () yields () { let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19 @@ -41,7 +41,7 @@ yields () _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16 // mir::Constant // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13 - // + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(<ZST>) } } bb2: { @@ -53,7 +53,7 @@ yields () _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16 // mir::Constant // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13 - // + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(<ZST>) } } bb3: { @@ -66,7 +66,7 @@ yields () } bb4: { - return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:6: 28:6 + return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:18: 22:18 } bb5: { @@ -82,7 +82,7 @@ yields () } bb7: { - generator_drop; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6 + generator_drop; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 22:18 } bb8 (cleanup): { @@ -104,7 +104,7 @@ yields () } bb11 (cleanup): { - resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6 + resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 22:18 } bb12 (cleanup): { diff --git a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 7f5ebe2a59b55..16fa432dc3ad3 100644 --- a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -14,31 +14,31 @@ }, } */ -fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]>, _2: u8) -> GeneratorState<(), ()> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 - let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 let mut _4: !; // in scope 0 at $DIR/generator-tiny.rs:21:9: 24:10 - let mut _5: (); // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + let mut _5: (); // in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 let _6: u8; // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18 let mut _7: (); // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18 let _8: (); // in scope 0 at $DIR/generator-tiny.rs:23:13: 23:21 let mut _9: (); // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25 let _10: u8; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 - let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 scope 1 { - debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15 + debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15 } bb0: { - _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 - switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 } bb1: { - _10 = move _2; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + _10 = move _2; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 nop; // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 - Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25 + Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25 StorageLive(_4); // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10 goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10 } @@ -50,7 +50,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6] Deinit(_0); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 - discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 return; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 } @@ -61,7 +61,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6] _8 = callee() -> bb4; // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21 // mir::Constant // + span: $DIR/generator-tiny.rs:23:13: 23:19 - // + literal: Const { ty: fn() {callee}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {callee}, val: Value(<ZST>) } } bb4: { @@ -71,14 +71,14 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6] } bb5: { - StorageLive(_4); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 - StorageLive(_6); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 - StorageLive(_7); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 - _6 = move _2; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 - goto -> bb3; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + StorageLive(_4); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + StorageLive(_6); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + StorageLive(_7); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + _6 = move _2; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 + goto -> bb3; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 } bb6: { - unreachable; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + unreachable; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24 } } diff --git a/src/test/mir-opt/inline/caller-with-trivial-bound.rs b/src/test/mir-opt/inline/caller-with-trivial-bound.rs new file mode 100644 index 0000000000000..8545db89414a7 --- /dev/null +++ b/src/test/mir-opt/inline/caller-with-trivial-bound.rs @@ -0,0 +1,26 @@ +// ignore-wasm32 compiled with panic=abort by default +// needs-unwind + +#![crate_type = "lib"] +pub trait Factory<T> { + type Item; +} + +pub struct IntFactory; + +impl<T> Factory<T> for IntFactory { + type Item = usize; +} + +// EMIT_MIR caller_with_trivial_bound.foo.Inline.diff +pub fn foo<T>() +where + IntFactory: Factory<T>, +{ + let mut x: <IntFactory as Factory<T>>::Item = bar::<T>(); +} + +#[inline(always)] +pub fn bar<T>() -> <IntFactory as Factory<T>>::Item { + 0usize +} diff --git a/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff new file mode 100644 index 0000000000000..d30c74897b342 --- /dev/null +++ b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff @@ -0,0 +1,33 @@ +- // MIR for `foo` before Inline ++ // MIR for `foo` after Inline + + fn foo() -> () { + let mut _0: (); // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:17:1: 17:1 + let mut _1: <IntFactory as Factory<T>>::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14 + scope 1 { + debug x => _1; // in scope 1 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14 + _1 = bar::<T>() -> bb1; // scope 0 at $DIR/caller-with-trivial-bound.rs:20:51: 20:61 + // mir::Constant + // + span: $DIR/caller-with-trivial-bound.rs:20:51: 20:59 + // + literal: Const { ty: fn() -> <IntFactory as Factory<T>>::Item {bar::<T>}, val: Value(<ZST>) } + } + + bb1: { + _0 = const (); // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 21:2 + drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:21:1: 21:2 + } + + bb2: { + StorageDead(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:21:1: 21:2 + return; // scope 0 at $DIR/caller-with-trivial-bound.rs:21:2: 21:2 + } + + bb3 (cleanup): { + resume; // scope 0 at $DIR/caller-with-trivial-bound.rs:16:1: 21:2 + } + } + diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff index d42b8397c505e..1376ba99d992c 100644 --- a/src/test/mir-opt/inline/cycle.f.Inline.diff +++ b/src/test/mir-opt/inline/cycle.f.Inline.diff @@ -17,7 +17,7 @@ _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:6:5: 6:8 // mir::Constant // + span: $DIR/cycle.rs:6:5: 6:6 - // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff index 450157e64284f..5a8c147a32723 100644 --- a/src/test/mir-opt/inline/cycle.g.Inline.diff +++ b/src/test/mir-opt/inline/cycle.g.Inline.diff @@ -5,11 +5,11 @@ let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8 let _1: (); // in scope 0 at $DIR/cycle.rs:12:5: 12:12 + let mut _2: fn() {main}; // in scope 0 at $DIR/cycle.rs:12:5: 12: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 + } + } @@ -21,15 +21,14 @@ + _2 = main; // scope 0 at $DIR/cycle.rs:12:5: 12:12 // mir::Constant - // + span: $DIR/cycle.rs:12:5: 12:6 -- // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(<ZST>) } - // mir::Constant // + span: $DIR/cycle.rs:12:7: 12:11 - // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {main}, val: Value(<ZST>) } + StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + 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 } @@ -49,7 +48,7 @@ + } + + bb4: { -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 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/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff index 5e2f70799e41e..e102c65090587 100644 --- a/src/test/mir-opt/inline/cycle.main.Inline.diff +++ b/src/test/mir-opt/inline/cycle.main.Inline.diff @@ -5,11 +5,11 @@ let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11 let _1: (); // in scope 0 at $DIR/cycle.rs:17:5: 17:9 + let mut _2: fn() {g}; // in scope 0 at $DIR/cycle.rs:17:5: 17: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 + scope 3 (inlined g) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL + let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12 @@ -31,15 +31,14 @@ + _2 = g; // scope 0 at $DIR/cycle.rs:17:5: 17:9 // mir::Constant - // + span: $DIR/cycle.rs:17:5: 17:6 -- // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(<ZST>) } - // mir::Constant // + span: $DIR/cycle.rs:17:7: 17:8 - // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } + StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + 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 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 + StorageLive(_7); // scope 4 at $DIR/cycle.rs:6:5: 6:8 + StorageLive(_8); // scope 4 at $DIR/cycle.rs:6:5: 6:6 @@ -66,7 +65,7 @@ + StorageDead(_8); // scope 4 at $DIR/cycle.rs:6:7: 6:8 + StorageDead(_7); // scope 4 at $DIR/cycle.rs:6:8: 6:9 + StorageDead(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 -+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 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/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff index d1ab29b8a21ab..7b306dd9482ca 100644 --- a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff +++ b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff @@ -28,7 +28,7 @@ // mir::Constant // + span: $DIR/dyn-trait.rs:33:13: 33:21 // + user_ty: UserType(0) - // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(<ZST>) } } bb1: { @@ -46,9 +46,9 @@ + _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn-trait.rs:34:5: 34:22 -- // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) } + // + span: $DIR/dyn-trait.rs:21:7: 21:20 -+ // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) } ++ // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff index 27309328052c7..2a909702a6dc0 100644 --- a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff +++ b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff @@ -12,7 +12,7 @@ _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 // mir::Constant // + span: $DIR/dyn-trait.rs:21:7: 21:20 - // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff index 0c44c3ada0f8c..01ebc999cb3ec 100644 --- a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff +++ b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff @@ -23,9 +23,9 @@ + _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 // mir::Constant - // + span: $DIR/dyn-trait.rs:27:5: 27:13 -- // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) } + // + span: $DIR/dyn-trait.rs:21:7: 21:20 -+ // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) } ++ // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index ade6ccfc7f144..ff338ae58cd87 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -21,7 +21,7 @@ fn bar() -> bool { _1 = foo; // scope 0 at $DIR/inline-any-operand.rs:11:13: 11:16 // mir::Constant // + span: $DIR/inline-any-operand.rs:11:13: 11:16 - // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(<ZST>) } StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index c6b49b66dc5c0..0e6ae6578e2a3 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -19,8 +19,8 @@ fn foo(_1: T, _2: i32) -> (i32, T) { debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18 let mut _10: i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 let mut _11: T; // in scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - let mut _12: &i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24 - let mut _13: &T; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24 + let mut _12: &i32; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:17 + let mut _13: &T; // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:17 } } @@ -33,8 +33,8 @@ fn foo(_1: T, _2: i32) -> (i32, T) { Deinit(_3); // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 (_3.0: &i32) = move _4; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 (_3.1: &T) = move _5; // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 - StorageDead(_5); // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24 - StorageDead(_4); // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageDead(_5); // scope 0 at $DIR/inline-closure-captures.rs:11:16: 11:17 + StorageDead(_4); // scope 0 at $DIR/inline-closure-captures.rs:11:16: 11:17 StorageLive(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6 _6 = &_3; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6 StorageLive(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 @@ -46,12 +46,12 @@ fn foo(_1: T, _2: i32) -> (i32, T) { _9 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 StorageLive(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - _12 = move ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 _10 = (*_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 StorageDead(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 StorageLive(_11); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 StorageLive(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - _13 = move ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 _11 = (*_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 StorageDead(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 Deinit(_0); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff index fd9a540ca16e2..34762b97c3b2f 100644 --- a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff @@ -12,7 +12,7 @@ - _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:24:5: 24:18 - // mir::Constant - // + span: $DIR/inline-compatibility.rs:24:5: 24:16 -- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) } - } - - bb1: { diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff index e7db7aa382fae..fd1e1983d1e0d 100644 --- a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff @@ -12,7 +12,7 @@ - _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:13:5: 13:21 - // mir::Constant - // + span: $DIR/inline-compatibility.rs:13:5: 13:19 -- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) } - } - - bb1: { diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff index 09bca903c80e8..bced3f6fe56a7 100644 --- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff @@ -13,7 +13,7 @@ _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline-compatibility.rs:42:13: 42:52 // mir::Constant // + span: $DIR/inline-compatibility.rs:42:13: 42:16 - // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff index 5af3946f2e501..a4989cbfa096d 100644 --- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff @@ -10,7 +10,7 @@ _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:29:5: 29:18 // mir::Constant // + span: $DIR/inline-compatibility.rs:29:5: 29:16 - // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff index 8c9fa573ce218..49dd90c971cb4 100644 --- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff @@ -10,7 +10,7 @@ _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:18:5: 18:21 // mir::Constant // + span: $DIR/inline-compatibility.rs:18:5: 18:19 - // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff index b732e7cdb9bf8..8128797d27eae 100644 --- a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff @@ -5,17 +5,20 @@ let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:13:10: 13:10 let _1: (); // in scope 0 at $DIR/inline-cycle.rs:14:5: 14:24 + scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle.rs:14:5: 14:24 ++ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline-cycle.rs:43:9: 43:23 ++ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline-cycle.rs:28:9: 28:31 ++ } ++ } + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24 - _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24 -+ _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline-cycle.rs:43:9: 43:23 ++ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline-cycle.rs:36:9: 36:28 // mir::Constant - // + span: $DIR/inline-cycle.rs:14:5: 14:22 -- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) } -+ // + span: $DIR/inline-cycle.rs:43:9: 43:21 -+ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(Scalar(<ZST>)) } ++ // + span: $DIR/inline-cycle.rs:36:9: 36:26 + // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff index eac5bf8edec4b..29c793d7bd8cd 100644 --- a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff @@ -5,12 +5,15 @@ let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:48:10: 48:10 let _1: (); // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 + let mut _2: fn() {f}; // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 -+ let mut _5: (); // 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: fn() {f}; // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:6 ++ let mut _5: (); // 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 ++ scope 3 (inlined f) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ let _6: (); // in scope 3 at $DIR/inline-cycle.rs:59:5: 59:12 ++ } + } + } @@ -21,20 +24,26 @@ + _2 = f; // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 // mir::Constant - // + span: $DIR/inline-cycle.rs:49:5: 49:9 -- // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(Scalar(<ZST>)) } -- // mir::Constant - // + span: $DIR/inline-cycle.rs:49:10: 49:11 - // + literal: Const { ty: fn() {f}, val: Value(Scalar(<ZST>)) } ++ // + 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(_4); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6 + _4 = move _2; // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6 + StorageLive(_5); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 -+ _5 = const (); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 -+ _3 = move _4() -> bb1; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ StorageLive(_6); // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12 ++ _6 = call::<fn() {f}>(f) -> bb1; // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12 ++ // mir::Constant ++ // + span: $DIR/inline-cycle.rs:59:5: 59:9 + // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) } + // mir::Constant +- // + span: $DIR/inline-cycle.rs:49:10: 49:11 ++ // + span: $DIR/inline-cycle.rs:59:10: 59:11 + // + literal: Const { ty: fn() {f}, val: Value(<ZST>) } } bb1: { -+ StorageDead(_5); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8 ++ StorageDead(_6); // scope 3 at $DIR/inline-cycle.rs:59:12: 59:13 ++ StorageDead(_5); // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8 + 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(_2); // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12 diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff index 267f53a8dfe7b..2ccd39e7931ed 100644 --- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff @@ -4,19 +4,33 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11 let _1: (); // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 ++ scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24 ++ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:38:9: 38:31 ++ scope 3 (inlined <A as Call>::call) { // at $DIR/inline-cycle-generic.rs:31:9: 31:28 ++ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline-cycle-generic.rs:23:9: 23:31 ++ } ++ } ++ } ++ } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 - _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 +- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 ++ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline-cycle-generic.rs:31:9: 31:28 // mir::Constant - // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22 - // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) } +- // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22 ++ // + span: $DIR/inline-cycle-generic.rs:31:9: 31:26 + // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) } } bb1: { StorageDead(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:24: 9:25 _0 = const (); // scope 0 at $DIR/inline-cycle-generic.rs:8:11: 10:2 return; // scope 0 at $DIR/inline-cycle-generic.rs:10:2: 10:2 ++ } ++ ++ bb2 (cleanup): { ++ resume; // scope 0 at $DIR/inline-cycle-generic.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff index ff25c5b4bc337..7cdc1a6b546a2 100644 --- a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff @@ -13,7 +13,7 @@ - _2 = sleep(); // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12 - // mir::Constant - // + span: $DIR/inline-diverging.rs:8:5: 8:10 -- // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) } + goto -> bb1; // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12 + } + diff --git a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff index da55260e284ea..595df0aed5ff8 100644 --- a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff @@ -38,9 +38,9 @@ + _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 -- // + literal: Const { ty: fn() -> ! {panic}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() -> ! {panic}, val: Value(<ZST>) } + // + span: $SRC_DIR/std/src/panic.rs:LL:COL -+ // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(Scalar(<ZST>)) } ++ // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) } + // mir::Constant + // + span: $SRC_DIR/std/src/panic.rs:LL:COL + // + literal: Const { ty: &str, val: Value(Slice(..)) } diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 0a19daa5045c9..32066cf2e3e73 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -5,20 +5,20 @@ let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12 let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16 -+ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28: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 _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:29:6: 29:7 -+ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10 ++ let mut _5: (); // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 ++ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14 ++ let mut _8: (); // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:16 ++ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7 ++ let mut _10: !; // 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 -+ let _5: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10 ++ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10 + scope 3 { -+ debug b => _5; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10 ++ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10 + } + scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16 + scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -38,15 +38,14 @@ + _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 // mir::Constant - // + span: $DIR/inline-diverging.rs:22:5: 22:15 -- // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(<ZST>) } - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 - // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) } + 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(_9); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 -+ _9 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 ++ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16 + goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12 + } + diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index 3e1c4a4670143..b4f0abd1af54b 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -4,22 +4,22 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11 let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11 - let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32 - let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31 - let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31 + let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32 + let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31 + let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31 + let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46 scope 1 { debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11 } + scope 2 (inlined g) { // at $DIR/inline-generator.rs:9:28: 9:31 + } -+ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32 ++ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32 + debug pointer => _3; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL -+ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL ++ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL + scope 4 { -+ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new_unchecked) { // at $SRC_DIR/core/src/pin.rs:LL:COL ++ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new_unchecked) { // at $SRC_DIR/core/src/pin.rs:LL:COL + debug pointer => _5; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL -+ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL ++ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + } + } + } @@ -29,10 +29,10 @@ + let mut _9: bool; // in scope 6 at $DIR/inline-generator.rs:15:20: 15:21 + let mut _10: bool; // in scope 6 at $DIR/inline-generator.rs:15:9: 15:9 + let _11: bool; // in scope 6 at $DIR/inline-generator.rs:15:6: 15:7 -+ let mut _12: u32; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ let mut _12: u32; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8 + } bb0: { @@ -43,18 +43,18 @@ - _4 = g() -> bb1; // scope 0 at $DIR/inline-generator.rs:9:28: 9:31 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:28: 9:29 -- // + literal: Const { ty: fn() -> impl Generator<bool> {g}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() -> impl Generator<bool> {g}, val: Value(<ZST>) } - } - - bb1: { + Deinit(_4); // scope 2 at $DIR/inline-generator.rs:15:5: 15:41 + discriminant(_4) = 0; // scope 2 at $DIR/inline-generator.rs:15:5: 15:41 _3 = &mut _4; // scope 0 at $DIR/inline-generator.rs:9:23: 9:31 -- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32 +- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:14: 9:22 - // + user_ty: UserType(0) -- // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new}, val: Value(<ZST>) } - } - - bb2: { @@ -63,24 +63,24 @@ + StorageLive(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + _6 = move _5; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + Deinit(_2); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL -+ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL ++ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + StorageDead(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL + StorageDead(_5); // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:9:31: 9:32 -- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 +- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 - // mir::Constant - // + span: $DIR/inline-generator.rs:9:33: 9:39 -- // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) } + StorageLive(_7); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + _7 = const false; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_12); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 -+ StorageLive(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ _13 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ StorageDead(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ StorageLive(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ _13 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ StorageDead(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 } - bb3: { @@ -102,7 +102,7 @@ + } + + bb3: { -+ _11 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ _11 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 + StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:17: 15:39 + StorageLive(_9); // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 + _9 = _11; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21 @@ -125,32 +125,32 @@ + ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + StorageLive(_14); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 -+ _14 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ _14 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + discriminant((*_14)) = 3; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + StorageDead(_14); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39 + } + + bb7: { -+ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ _10 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 ++ _10 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 + StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39 -+ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ StorageLive(_15); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ _15 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ discriminant((*_15)) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ StorageDead(_15); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:41: 15:41 ++ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ StorageLive(_15); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ _15 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ discriminant((*_15)) = 1; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ StorageDead(_15); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8 ++ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:8: 15:8 + } + + bb8: { -+ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 + } + + bb9: { -+ unreachable; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ unreachable; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8 } } diff --git a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff index 65891cbb660e1..05bd99b62cd1f 100644 --- a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff +++ b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff @@ -14,7 +14,7 @@ _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26 // mir::Constant // + span: $DIR/inline-instruction-set.rs:51:5: 51:24 - // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) } } bb1: { @@ -23,7 +23,7 @@ _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26 // mir::Constant // + span: $DIR/inline-instruction-set.rs:52:5: 52:24 - // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) } } bb2: { @@ -32,7 +32,7 @@ - _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30 - // mir::Constant - // + span: $DIR/inline-instruction-set.rs:53:5: 53:28 -- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) } - } - - bb3: { diff --git a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff index 20e1d0ae4d5da..cb0d01428c946 100644 --- a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff +++ b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff @@ -14,7 +14,7 @@ _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26 // mir::Constant // + span: $DIR/inline-instruction-set.rs:42:5: 42:24 - // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) } } bb1: { @@ -23,7 +23,7 @@ - _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26 - // mir::Constant - // + span: $DIR/inline-instruction-set.rs:43:5: 43:24 -- // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) } - } - - bb2: { @@ -33,7 +33,7 @@ + _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30 // mir::Constant // + span: $DIR/inline-instruction-set.rs:46:5: 46:28 - // + literal: Const { ty: fn() {instruction_set_default}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) } } - bb3: { diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index 89414574898a6..17050f184cb48 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -28,7 +28,7 @@ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 // mir::Constant // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { @@ -44,7 +44,7 @@ // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 - // + user_ty: UserType(1) -- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) } - } - - bb2: { @@ -75,7 +75,7 @@ - _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 -- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) } - } - - bb5 (cleanup): { diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index 89414574898a6..17050f184cb48 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -28,7 +28,7 @@ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 // mir::Constant // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { @@ -44,7 +44,7 @@ // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 - // + user_ty: UserType(1) -- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) } - } - - bb2: { @@ -75,7 +75,7 @@ - _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 -- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) } - } - - bb5 (cleanup): { diff --git a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir index eca76df576bf6..45023083be668 100644 --- a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir @@ -15,7 +15,7 @@ fn main() -> () { _1 = not_inlined() -> bb1; // scope 0 at $DIR/inline-options.rs:9:5: 9:18 // mir::Constant // + span: $DIR/inline-options.rs:9:5: 9:16 - // + literal: Const { ty: fn() {not_inlined}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {not_inlined}, val: Value(<ZST>) } } bb1: { @@ -25,7 +25,7 @@ fn main() -> () { _3 = g() -> bb2; // 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(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } } bb2: { @@ -34,7 +34,7 @@ fn main() -> () { _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(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } } bb3: { @@ -43,7 +43,7 @@ fn main() -> () { _5 = g() -> bb4; // 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(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {g}, val: Value(<ZST>) } } bb4: { diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 2d85ff9a0cbc2..fcc1767578eb2 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -27,7 +27,7 @@ fn bar() -> bool { _1 = foo; // scope 0 at $DIR/inline-retag.rs:11:13: 11:16 // mir::Constant // + span: $DIR/inline-retag.rs:11:13: 11:16 - // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value(<ZST>) } StorageLive(_2); // scope 1 at $DIR/inline-retag.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-retag.rs:12:5: 12:6 StorageLive(_3); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 diff --git a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff index 7170cd4057200..d67b07b0181b4 100644 --- a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff +++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff @@ -14,7 +14,7 @@ - _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 - // mir::Constant - // + span: $DIR/inline-shims.rs:6:7: 6:12 -- // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(<ZST>) } - } - - bb1: { diff --git a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff index aa55c90fcfb55..5c7cbc9b41900 100644 --- a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff +++ b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff @@ -24,7 +24,7 @@ _3 = std::ptr::drop_in_place::<Vec<A>>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:11:14: 11:40 // mir::Constant // + span: $DIR/inline-shims.rs:11:14: 11:37 - // + literal: Const { ty: unsafe fn(*mut Vec<A>) {std::ptr::drop_in_place::<Vec<A>>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(*mut Vec<A>) {std::ptr::drop_in_place::<Vec<A>>}, val: Value(<ZST>) } } bb1: { @@ -35,7 +35,7 @@ - _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 - // mir::Constant - // + span: $DIR/inline-shims.rs:12:14: 12:37 -- // + literal: Const { ty: unsafe fn(*mut Option<B>) {std::ptr::drop_in_place::<Option<B>>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: unsafe fn(*mut Option<B>) {std::ptr::drop_in_place::<Option<B>>}, val: Value(<ZST>) } + StorageLive(_6); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 + StorageLive(_7); // scope 2 at $DIR/inline-shims.rs:12:14: 12:40 + _6 = discriminant((*_5)); // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff index 8e93baf6a7050..747eeb9845073 100644 --- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff @@ -15,7 +15,7 @@ - _1 = <Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 - // mir::Constant - // + span: $DIR/inline-specialization.rs:5:13: 5:36 -- // + literal: Const { ty: fn() -> u32 {<Vec<()> as Foo>::bar}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: fn() -> u32 {<Vec<()> as Foo>::bar}, val: Value(<ZST>) } - } - - bb1: { diff --git a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir index 0be979901ac03..1646de9289a81 100644 --- a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir @@ -11,7 +11,7 @@ fn test(_1: &dyn X) -> u32 { _0 = <dyn X as X>::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 // mir::Constant // + span: $DIR/inline-trait-method.rs:9:7: 9:8 - // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {<dyn X as X>::y}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 64375b6edc93e..eb6c09c1cd798 100644 --- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -21,7 +21,7 @@ fn test2(_1: &dyn X) -> bool { _0 = <dyn X as X>::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8 - // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 11a205eb41580..b45dfb17bfe82 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -22,7 +22,7 @@ fn b(_1: &mut Box<T>) -> &mut T { StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _7 = move (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _7 = deref_copy (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_8); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _8 = (((_7.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _6 = &mut (*_8); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index b04a91d7c9590..4e8547419ae1f 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -16,7 +16,7 @@ fn d(_1: &Box<T>) -> &T { StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageLive(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _4 = move (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _4 = deref_copy (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _5 = (((_4.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _2 = &(*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir index 7c3048a69af61..242073574f2b2 100644 --- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir @@ -2,8 +2,8 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:4:11: 4:11 - let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:33]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 - let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:33]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6 + let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10 + let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6 let mut _3: ((),); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 let mut _4: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9 let mut _5: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10 diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff index b44f9900d6c6a..f91d352622626 100644 --- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff +++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff @@ -19,7 +19,7 @@ + _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:13 - // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) } } bb1: { @@ -29,7 +29,7 @@ - _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 - // mir::Constant - // + span: $DIR/issue-78442.rs:11:5: 11:15 -- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) } + _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL } diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff index 8a998fb50006c..4446280e72004 100644 --- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff +++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff @@ -18,7 +18,7 @@ _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:13 - // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) } } bb1: { @@ -29,8 +29,8 @@ + _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 // mir::Constant // + span: $DIR/issue-78442.rs:11:5: 11:15 -- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) } -+ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) } ++ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 34ba7dfdcc5bb..9384ce52cc825 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -22,7 +22,7 @@ _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 // mir::Constant // + span: /the/src/instrument_coverage.rs:12:12: 12:15 - // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir index 7113c42b9c77f..19110894dc720 100644 --- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir @@ -23,7 +23,7 @@ fn main() -> () { _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // mir::Constant // + span: $DIR/issue-41110.rs:8:23: 8:25 - // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(<ZST>) } } bb1: { @@ -32,7 +32,7 @@ fn main() -> () { _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // mir::Constant // + span: $DIR/issue-41110.rs:8:15: 8:20 - // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(S, S) {S::other}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir index c4e852ca3212a..1901ea1747ed2 100644 --- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir @@ -28,7 +28,7 @@ fn test() -> () { _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // mir::Constant // + span: $DIR/issue-41110.rs:17:5: 17:9 - // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir index db9caf843145b..701e291f46ecf 100644 --- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/issue-41697.rs:18:1: 22:2>::{constant#0}` after SimplifyCfg-promote-consts +// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts -<impl at $DIR/issue-41697.rs:18:1: 22:2>::{constant#0}: usize = { +<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir index db9caf843145b..701e291f46ecf 100644 --- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/issue-41697.rs:18:1: 22:2>::{constant#0}` after SimplifyCfg-promote-consts +// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts -<impl at $DIR/issue-41697.rs:18:1: 22:2>::{constant#0}: usize = { +<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir index ce7ca20358e12..a4ff718f42258 100644 --- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir @@ -29,7 +29,7 @@ fn main() -> () { _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // mir::Constant // + span: $DIR/issue-41888.rs:8:8: 8:12 - // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/issue_49232.main.mir_map.0.mir b/src/test/mir-opt/issue_49232.main.mir_map.0.mir index 2f8931382a69e..6301763449b90 100644 --- a/src/test/mir-opt/issue_49232.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_49232.main.mir_map.0.mir @@ -59,7 +59,7 @@ fn main() -> () { _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22 // mir::Constant // + span: $DIR/issue-49232.rs:13:9: 13:13 - // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(<ZST>) } } bb9: { diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index 4d06b91e6dc61..f21e9bbd270a2 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -34,7 +34,7 @@ fn test() -> Option<Box<u32>> { _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 // mir::Constant // + span: $DIR/issue-62289.rs:9:10: 9:21 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { @@ -46,7 +46,7 @@ fn test() -> Option<Box<u32>> { _6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(Option<u32>) -> ControlFlow<<Option<u32> as Try>::Residual, <Option<u32> as Try>::Output> {<Option<u32> as Try>::branch}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(Option<u32>) -> ControlFlow<<Option<u32> as Try>::Residual, <Option<u32> as Try>::Output> {<Option<u32> as Try>::branch}, val: Value(<ZST>) } } bb2: { @@ -76,7 +76,7 @@ fn test() -> Option<Box<u32>> { _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(Option<Infallible>) -> Option<Box<u32>> {<Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(Option<Infallible>) -> Option<Box<u32>> {<Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual}, val: Value(<ZST>) } } bb6: { diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir index 2e6783b7f3c9d..f4602d147c947 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir @@ -25,7 +25,7 @@ fn main() -> () { _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 // mir::Constant // + span: $DIR/issue-72181.rs:24:13: 24:32 - // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir index 2e6783b7f3c9d..f4602d147c947 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir @@ -25,7 +25,7 @@ fn main() -> () { _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 // mir::Constant // + span: $DIR/issue-72181.rs:24:13: 24:32 - // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index 899c84687890b..9842e26ab6993 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -24,7 +24,7 @@ fn main() -> () { _2 = transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 // mir::Constant // + span: $DIR/issue-72181-1.rs:17:9: 17:40 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(<ZST>) } } bb1: { @@ -37,7 +37,7 @@ fn main() -> () { _4 = f(move _5) -> bb4; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 // mir::Constant // + span: $DIR/issue-72181-1.rs:20:5: 20:6 - // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index 8b0a73ec4ba61..9295265154424 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -98,7 +98,7 @@ _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index 8b0a73ec4ba61..9295265154424 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -98,7 +98,7 @@ _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index c96a6641bab91..f52b1a953c120 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -135,7 +135,7 @@ _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index c96a6641bab91..f52b1a953c120 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -135,7 +135,7 @@ _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index 29bcef26518a1..14bb66910fe3c 100644 --- a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -70,7 +70,7 @@ _22 = 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 - // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/core/src/panic.rs:LL:COL // + literal: Const { ty: &str, val: Value(Slice(..)) } diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 40e7b74453a7c..dd85434d879c3 100644 --- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -39,7 +39,7 @@ fn num_to_digit(_1: char) -> u32 { _7 = char::methods::<impl char>::to_digit(move _8, const 8_u32) -> bb5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/char/methods.rs:LL:COL - // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) } } bb1: { @@ -50,7 +50,7 @@ fn num_to_digit(_1: char) -> u32 { _3 = char::methods::<impl char>::to_digit(move _4, const 8_u32) -> bb2; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41 // mir::Constant // + span: $DIR/issue-59352.rs:14:30: 14:38 - // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) } } bb2: { @@ -90,7 +90,7 @@ fn num_to_digit(_1: char) -> u32 { _11 = 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 - // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/core/src/option.rs:LL:COL // + literal: Const { ty: &str, val: Value(Slice(..)) } diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index b8023a6a8e690..08ff3b67655ce 100644 --- a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -27,7 +27,7 @@ _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:7:37: 7:53 // mir::Constant // + span: $DIR/issue-75439.rs:7:37: 7:46 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) } } bb1: { @@ -50,7 +50,7 @@ _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue-75439.rs:10:23: 10:36 // mir::Constant // + span: $DIR/issue-75439.rs:10:23: 10:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) } } bb5: { diff --git a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff index 3f5f71f80825d..1b9e46c6a6d0a 100644 --- a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff @@ -8,7 +8,7 @@ - _0 = std::intrinsics::min_align_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:19:5: 19:40 -- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(<ZST>) } + _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42 } diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index 88d2867fc42ab..9bda88ce2c7e8 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -32,7 +32,7 @@ - _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:74:5: 74:41 -- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) } + _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45 } @@ -53,7 +53,7 @@ - _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:75:5: 75:41 -- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) } + _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45 } @@ -74,7 +74,7 @@ - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:76:5: 76:41 -- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) } + _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 + goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46 } @@ -95,7 +95,7 @@ - _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:77:5: 77:41 -- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) } + _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 + goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48 } diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir index 7750624db30fb..a12aa1d6686a9 100644 --- a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir @@ -20,7 +20,7 @@ fn f_u64() -> () { _2 = f_non_zst::<u64>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 // mir::Constant // + span: $DIR/lower_intrinsics.rs:48:9: 48:18 - // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir index 4d4e65d311416..49e3b9144a59a 100644 --- a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir @@ -6,6 +6,7 @@ fn f_unit() -> () { scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19 debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23 let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 + let mut _3: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16 scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32 } } @@ -13,13 +14,15 @@ fn f_unit() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18 StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 - _2 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16 + _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 // mir::Constant // + span: $DIR/lower_intrinsics.rs:46:9: 46:14 - // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) } } bb1: { + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:16: 46:17 StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:17: 46:18 StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:34:18: 34:19 return; // scope 0 at $DIR/lower_intrinsics.rs:35:2: 35:2 diff --git a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff index 7e1e066366c11..6c99e1b7ca6cb 100644 --- a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff @@ -12,7 +12,7 @@ - _0 = std::intrinsics::forget::<T>(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:24:5: 24:29 -- // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(<ZST>) } + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32 } diff --git a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff index 276227d8c018a..41dac17dcb640 100644 --- a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff @@ -14,7 +14,7 @@ _1 = std::intrinsics::size_of::<T>; // scope 0 at $DIR/lower_intrinsics.rs:62:21: 62:51 // mir::Constant // + span: $DIR/lower_intrinsics.rs:62:21: 62:51 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) } StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14 _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14 - _0 = move _2() -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16 diff --git a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff index b5a77702a8ef0..cd6da6f1dc745 100644 --- a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff @@ -8,7 +8,7 @@ - _0 = std::intrinsics::size_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:14:5: 14:35 -- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) } + _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37 } diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index eb463afbf7795..0ce8d85070c70 100644 --- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -15,7 +15,7 @@ - _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:29:14: 29:43 -- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45 } diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff index 5a0286bad2fb7..ebe240121cc5f 100644 --- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff @@ -33,7 +33,7 @@ - _3 = wrapping_add::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:7:14: 7:44 -- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(<ZST>) } + _3 = Add(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50 } @@ -49,7 +49,7 @@ - _6 = wrapping_sub::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:8:14: 8:44 -- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(<ZST>) } + _6 = Sub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50 } @@ -65,7 +65,7 @@ - _9 = wrapping_mul::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:9:14: 9:44 -- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(<ZST>) } + _9 = Mul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50 } diff --git a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff index 13241d882f210..96404f0506cf2 100644 --- a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff +++ b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff @@ -23,7 +23,7 @@ - _5 = core::slice::<impl [u8]>::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - // mir::Constant - // + span: $DIR/lower_slice_len.rs:5:22: 5:25 -- // + literal: Const { ty: for<'r> fn(&'r [u8]) -> usize {core::slice::<impl [u8]>::len}, val: Value(Scalar(<ZST>)) } +- // + literal: Const { ty: for<'r> fn(&'r [u8]) -> usize {core::slice::<impl [u8]>::len}, val: Value(<ZST>) } + _5 = Len((*_6)); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + goto -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 } diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index 0d0204e126a6c..722097630f79b 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -61,7 +61,7 @@ fn full_tested_match() -> () { _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:14:20: 14:27 // mir::Constant // + span: $DIR/match_false_edges.rs:14:20: 14:25 - // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) } } bb6: { diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir index 270cc85ce032a..df052e32157db 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir @@ -62,7 +62,7 @@ fn full_tested_match2() -> () { _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:25:20: 25:27 // mir::Constant // + span: $DIR/match_false_edges.rs:25:20: 25:25 - // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) } } bb6: { diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir index 2f76e0137bd69..fc50db397fdcf 100644 --- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir @@ -70,7 +70,7 @@ fn main() -> () { _8 = guard() -> [return: bb6, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:34:21: 34:28 // mir::Constant // + span: $DIR/match_false_edges.rs:34:21: 34:26 - // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) } } bb6: { @@ -113,7 +113,7 @@ fn main() -> () { _12 = guard2(move _13) -> [return: bb11, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:36:20: 36:29 // mir::Constant // + span: $DIR/match_false_edges.rs:36:20: 36:26 - // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(<ZST>) } } bb11: { diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 7d9e012bb296e..e1d870ef9a4e9 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -70,30 +70,30 @@ fn main() -> () { StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 - _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 - // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) } } bb3: { StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 - _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 + _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb4: { StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 - _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 + _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 - // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) } } bb5: { StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 - _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 + _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index c555e0441f423..2f9dff00b631b 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -70,30 +70,30 @@ fn main() -> () { StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17 - _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 + _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14 - // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) } } bb3: { StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18 StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19 - _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 + _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6 goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } bb4: { StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 - _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 + _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18 // mir::Constant // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14 - // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) } } bb5: { StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19 - _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 + _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6 goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6 } diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir index 8a297cea2b956..fda6cd6120771 100644 --- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir @@ -23,7 +23,7 @@ fn unwrap(_1: Option<T>) -> T { _4 = begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/panic.rs:LL:COL - // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) } // mir::Constant // + span: $SRC_DIR/std/src/panic.rs:LL:COL // + literal: Const { ty: &str, val: Value(Slice(..)) } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index bdab2d9322210..0c814fd9d8dda 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -20,7 +20,7 @@ fn main() -> () { _2 = <str as ToString>::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32 - // + literal: Const { ty: for<'r> fn(&'r str) -> String {<str as ToString>::to_string}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r str) -> String {<str as ToString>::to_string}, val: Value(<ZST>) } } bb1: { @@ -28,7 +28,7 @@ fn main() -> () { _1 = std::mem::drop::<String>(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 - // + literal: Const { ty: fn(String) {std::mem::drop::<String>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(String) {std::mem::drop::<String>}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir index 5bf8655fcecdc..8ee81e679ec47 100644 --- a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir +++ b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir @@ -32,7 +32,7 @@ fn main() -> () { _1 = null_mut::<Test>() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/receiver-ptr-mutability.rs:14:26: 14:46 // mir::Constant // + span: $DIR/receiver-ptr-mutability.rs:14:26: 14:44 - // + literal: Const { ty: fn() -> *mut Test {null_mut::<Test>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> *mut Test {null_mut::<Test>}, val: Value(<ZST>) } } bb1: { @@ -47,7 +47,7 @@ fn main() -> () { _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 // mir::Constant // + span: $DIR/receiver-ptr-mutability.rs:15:9: 15:10 - // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) } } bb2: { @@ -75,7 +75,7 @@ fn main() -> () { _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 // mir::Constant // + span: $DIR/receiver-ptr-mutability.rs:19:13: 19:14 - // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index 447fe654c0cca..b2bfe4280b0af 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -60,7 +60,7 @@ _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir index 69742d6bc3b6a..05e83b13a50c4 100644 --- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir @@ -81,7 +81,7 @@ fn array_casts() -> () { _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:60:15: 60:23 // mir::Constant // + span: $DIR/retag.rs:60:17: 60:20 - // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(<ZST>) } } bb1: { @@ -112,7 +112,7 @@ fn array_casts() -> () { _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:64:26: 64:34 // mir::Constant // + span: $DIR/retag.rs:64:28: 64:31 - // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(<ZST>) } } bb2: { @@ -129,6 +129,7 @@ fn array_casts() -> () { _18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _13 = (move _14, move _18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Retag(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_20); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -171,10 +172,11 @@ fn array_casts() -> () { Retag(_32); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _34 = Option::<Arguments>::None; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Retag(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r usize, &'s usize, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<usize, usize>}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r usize, &'s usize, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<usize, usize>}, val: Value(<ZST>) } } bb4: { diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir index 09cf06cacd920..8057aa13a9ffb 100644 --- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir +++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir @@ -11,7 +11,7 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () { _3 = <Test as Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut Test) {<Test as Drop>::drop}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r mut Test) {<Test as Drop>::drop}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir index 0b8c4d25d2d3c..5808c60775252 100644 --- a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir @@ -9,14 +9,14 @@ fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 { } bb0: { - Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:40:31: 43:6 - Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:40:31: 43:6 + Retag([fn entry] _1); // scope 0 at $DIR/retag.rs:40:31: 40:48 + Retag([fn entry] _2); // scope 0 at $DIR/retag.rs:40:31: 40:48 StorageLive(_3); // scope 0 at $DIR/retag.rs:41:13: 41:15 _3 = _2; // scope 0 at $DIR/retag.rs:41:18: 41:19 Retag(_3); // scope 0 at $DIR/retag.rs:41:18: 41:19 _0 = _2; // scope 1 at $DIR/retag.rs:42:9: 42:10 Retag(_0); // scope 1 at $DIR/retag.rs:42:9: 42:10 StorageDead(_3); // scope 0 at $DIR/retag.rs:43:5: 43:6 - return; // scope 0 at $DIR/retag.rs:43:6: 43:6 + return; // scope 0 at $DIR/retag.rs:40:48: 40:48 } } diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index 2fda8c949b00c..a3490d460ec54 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -74,7 +74,7 @@ fn main() -> () { _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:32:17: 32:36 // mir::Constant // + span: $DIR/retag.rs:32:25: 32:28 - // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) } } bb1: { @@ -121,7 +121,7 @@ fn main() -> () { // ] Retag(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 _13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:40:31: 43:6 - StorageDead(_14); // scope 1 at $DIR/retag.rs:43:5: 43:6 + StorageDead(_14); // scope 1 at $DIR/retag.rs:40:47: 40:48 StorageLive(_15); // scope 6 at $DIR/retag.rs:44:9: 44:11 StorageLive(_16); // scope 6 at $DIR/retag.rs:44:14: 44:15 _16 = _13; // scope 6 at $DIR/retag.rs:44:14: 44:15 @@ -159,7 +159,7 @@ fn main() -> () { _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:47:5: 47:24 // mir::Constant // + span: $DIR/retag.rs:47:13: 47:20 - // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) } } bb4: { @@ -183,7 +183,7 @@ fn main() -> () { _27 = array_casts() -> bb6; // scope 8 at $DIR/retag.rs:52:5: 52:18 // mir::Constant // + span: $DIR/retag.rs:52:5: 52:16 - // + literal: Const { ty: fn() {array_casts}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {array_casts}, val: Value(<ZST>) } } bb6: { diff --git a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir index f9ed3932d3335..980f07d5f1096 100644 --- a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/retag.rs:11:1: 19:2>::foo` after SimplifyCfg-elaborate-drops +// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo` after SimplifyCfg-elaborate-drops -fn <impl at $DIR/retag.rs:11:1: 19:2>::foo(_1: &Test, _2: &mut i32) -> &mut i32 { +fn <impl at $DIR/retag.rs:11:1: 11:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 { debug self => _1; // in scope 0 at $DIR/retag.rs:13:16: 13:21 debug x => _2; // in scope 0 at $DIR/retag.rs:13:23: 13:24 let mut _0: &mut i32; // return place in scope 0 at $DIR/retag.rs:13:42: 13:53 diff --git a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir index 87a8603a931da..9c252d63fc72c 100644 --- a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/retag.rs:11:1: 19:2>::foo_shr` after SimplifyCfg-elaborate-drops +// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo_shr` after SimplifyCfg-elaborate-drops -fn <impl at $DIR/retag.rs:11:1: 19:2>::foo_shr(_1: &Test, _2: &i32) -> &i32 { +fn <impl at $DIR/retag.rs:11:1: 11:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 { debug self => _1; // in scope 0 at $DIR/retag.rs:16:20: 16:25 debug x => _2; // in scope 0 at $DIR/retag.rs:16:27: 16:28 let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:16:42: 16:49 diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff index 1c5a890023648..6d41d5b7437f5 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff @@ -21,7 +21,7 @@ + _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:9:12: 9:15 - // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) } } - bb3: { diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff index b079bd7b57c42..78841d28b85b1 100644 --- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff +++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff @@ -22,7 +22,7 @@ + _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17 // mir::Constant // + span: $DIR/simplify_cfg.rs:9:12: 9:15 - // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff index d11c70b1efec6..f729b53b20410 100644 --- a/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff +++ b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff @@ -18,7 +18,7 @@ _2 = noop() -> bb2; // scope 0 at $DIR/simplify_if.rs:7:9: 7:15 // mir::Constant // + span: $DIR/simplify_if.rs:7:9: 7:13 - // + literal: Const { ty: fn() {noop}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {noop}, val: Value(<ZST>) } } bb2: { diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index 1bba1e9e88a4e..f4f1b9d4eb87e 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -15,7 +15,8 @@ - let mut _10: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 - let mut _11: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 + let _1: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 -+ let _2: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 ++ let mut _2: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 ++ let _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 scope 1 { } @@ -32,12 +33,13 @@ - StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20 - StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 - StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 -- _4 = use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 +- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 + StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 -+ _1 = use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 ++ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 ++ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 - // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) } } bb1: { @@ -49,19 +51,20 @@ - StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 - StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34 - _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 ++ StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:21: 14:22 + StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23 -+ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 -+ _2 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 ++ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 ++ _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 // mir::Constant // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11 - // + literal: Const { ty: fn(u8) {use_u8}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) } } bb2: { - StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:34: 16:35 - StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 - StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 -+ StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 ++ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:17:2: 17:2 } } diff --git a/src/test/mir-opt/simplify_match.main.ConstProp.diff b/src/test/mir-opt/simplify_match.main.ConstProp.diff index 1c8d043a6030c..6314abe6f39db 100644 --- a/src/test/mir-opt/simplify_match.main.ConstProp.diff +++ b/src/test/mir-opt/simplify_match.main.ConstProp.diff @@ -29,7 +29,7 @@ _0 = noop() -> bb3; // scope 0 at $DIR/simplify_match.rs:7:17: 7:23 // mir::Constant // + span: $DIR/simplify_match.rs:7:17: 7:21 - // + literal: Const { ty: fn() {noop}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {noop}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir index e0875ab0069e7..2c4738aa86618 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir +++ b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir @@ -198,6 +198,6 @@ static XXX: &Foo = { _0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 StorageDead(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 - return; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:1: 23:3 + return; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:1: 5:25 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index d7d2cdf9b0c75..d36d369003a63 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -33,7 +33,7 @@ fn move_out_by_subslice() -> () { _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { @@ -52,7 +52,7 @@ fn move_out_by_subslice() -> () { _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index 18bc1a17c1b50..e6c8b66c25af0 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -33,7 +33,7 @@ fn move_out_from_end() -> () { _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb1: { @@ -52,7 +52,7 @@ fn move_out_from_end() -> () { _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 // mir::Constant // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } bb3: { diff --git a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff index 70486f546d71b..5aa4f1b343249 100644 --- a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff @@ -22,7 +22,7 @@ _1 = empty() -> bb1; // scope 1 at $DIR/unreachable.rs:9:23: 9:30 // mir::Constant // + span: $DIR/unreachable.rs:9:23: 9:28 - // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff index d9f2681d145e6..b95ab881ef05d 100644 --- a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff +++ b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff @@ -24,7 +24,7 @@ _2 = empty() -> bb1; // scope 2 at $DIR/unreachable_diverging.rs:14:25: 14:32 // mir::Constant // + span: $DIR/unreachable_diverging.rs:14:25: 14:30 - // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(<ZST>) } } bb1: { @@ -48,7 +48,7 @@ + _5 = loop_forever() -> bb4; // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27 // mir::Constant // + span: $DIR/unreachable_diverging.rs:16:13: 16:25 - // + literal: Const { ty: fn() {loop_forever}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() {loop_forever}, val: Value(<ZST>) } } bb4: { diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir index d106da84fc778..028281ba4501c 100644 --- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir @@ -1,12 +1,12 @@ // MIR for `Test::X` 0 mir_map fn Test::X(_1: usize) -> Test { - let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 + let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 bb0: { - Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 - ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 - discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 - return; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 + Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + return; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 } } diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir index d106da84fc778..028281ba4501c 100644 --- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir @@ -1,12 +1,12 @@ // MIR for `Test::X` 0 mir_map fn Test::X(_1: usize) -> Test { - let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 + let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 bb0: { - Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 - ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 - discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 - return; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13 + Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 + return; // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6 } } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir index 5dc81b787a9fa..54ecaccdb4fb8 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir @@ -34,6 +34,6 @@ fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () { _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) } } } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir index 5dc81b787a9fa..54ecaccdb4fb8 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir @@ -34,6 +34,6 @@ fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () { _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) } } } diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir index a046a89bc8cf2..c41fe61d48bf1 100644 --- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir +++ b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir @@ -1,10 +1,10 @@ -// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 11:2>::ASSOCIATED_CONSTANT` 0 mir_map +// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map -const <impl at $DIR/unusual-item-types.rs:9:1: 11:2>::ASSOCIATED_CONSTANT: i32 = { +const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = { let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35 bb0: { _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39 - return; // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:40 + return; // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:35 } } diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir index a046a89bc8cf2..c41fe61d48bf1 100644 --- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir +++ b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir @@ -1,10 +1,10 @@ -// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 11:2>::ASSOCIATED_CONSTANT` 0 mir_map +// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map -const <impl at $DIR/unusual-item-types.rs:9:1: 11:2>::ASSOCIATED_CONSTANT: i32 = { +const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = { let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35 bb0: { _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39 - return; // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:40 + return; // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:35 } } diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir index ec2d161251b00..f1c5d95df1903 100644 --- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -19,7 +19,7 @@ fn while_loop(_1: bool) -> () { _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while-storage.rs:10:11: 10:22 // mir::Constant // + span: $DIR/while-storage.rs:10:11: 10:19 - // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) } } bb2: { @@ -34,7 +34,7 @@ fn while_loop(_1: bool) -> () { _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:11:12: 11:23 // mir::Constant // + span: $DIR/while-storage.rs:11:12: 11:20 - // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) } } bb4: { diff --git a/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile b/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile index 6e25eb7e45945..eb6ad9bd1a7da 100644 --- a/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile +++ b/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile @@ -1,4 +1,4 @@ -include ../tools.mk all: - $(RUSTC) --edition=2021 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg no_global_oom_handling + $(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg no_global_oom_handling diff --git a/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs b/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs index e9b28504a907a..47d90b1856be5 100644 --- a/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs +++ b/src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs @@ -3,7 +3,7 @@ #![no_core] extern "rust-intrinsic" { - fn atomic_xadd<T>(dst: *mut T, src: T) -> T; + fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T; } #[lang = "sized"] @@ -17,50 +17,50 @@ impl<T: ?Sized> Copy for *mut T {} #[cfg(target_has_atomic = "8")] pub unsafe fn atomic_u8(x: *mut u8) { - atomic_xadd(x, 1); - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "8")] pub unsafe fn atomic_i8(x: *mut i8) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "16")] pub unsafe fn atomic_u16(x: *mut u16) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "16")] pub unsafe fn atomic_i16(x: *mut i16) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "32")] pub unsafe fn atomic_u32(x: *mut u32) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "32")] pub unsafe fn atomic_i32(x: *mut i32) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "64")] pub unsafe fn atomic_u64(x: *mut u64) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "64")] pub unsafe fn atomic_i64(x: *mut i64) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "128")] pub unsafe fn atomic_u128(x: *mut u128) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "128")] pub unsafe fn atomic_i128(x: *mut i128) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "ptr")] pub unsafe fn atomic_usize(x: *mut usize) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } #[cfg(target_has_atomic = "ptr")] pub unsafe fn atomic_isize(x: *mut isize) { - atomic_xadd(x, 1); + atomic_xadd_seqcst(x, 1); } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt index e463099a5ee47..09ad276aa45ae 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt @@ -37,7 +37,7 @@ 37| 0| countdown = 10; 38| 0| } 39| 0| "alt string 2".to_owned() - 40| 0| }; + 40| | }; 41| 1| println!( 42| 1| "The string or alt: {}" 43| 1| , @@ -79,7 +79,7 @@ 79| 0| countdown = 10; 80| 1| } 81| 1| "alt string 4".to_owned() - 82| 1| }; + 82| | }; 83| 1| println!( 84| 1| "The string or alt: {}" 85| 1| , @@ -101,7 +101,7 @@ 101| 0| countdown = 10; 102| 5| } 103| 5| format!("'{}'", val) - 104| 5| }; + 104| | }; 105| 1| println!( 106| 1| "Repeated, quoted string: {:?}" 107| 1| , @@ -125,7 +125,7 @@ 125| 0| countdown = 10; 126| 0| } 127| 0| "closure should be unused".to_owned() - 128| 0| }; + 128| | }; 129| | 130| 1| let mut countdown = 10; 131| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; @@ -177,7 +177,7 @@ 173| 0| println!( 174| 0| "not called: {}", 175| 0| if is_true { "check" } else { "me" } - 176| 0| ) + 176| | ) 177| | ; 178| | 179| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = @@ -187,7 +187,7 @@ 183| 0| "not called: {}", 184| 0| if is_true { "check" } else { "me" } 185| | ) - 186| 0| } + 186| | } 187| | ; 188| | 189| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = @@ -196,7 +196,7 @@ 192| 1| "not called: {}", 193| 1| if is_true { "check" } else { "me" } ^0 - 194| 1| ) + 194| | ) 195| | ; 196| | 197| 1| let short_used_covered_closure_line_break_block_embedded_branch = @@ -207,7 +207,7 @@ 202| 1| if is_true { "check" } else { "me" } ^0 203| | ) - 204| 1| } + 204| | } 205| | ; 206| | 207| 1| if is_false { diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt index 0fb3808ff2e30..d70e12e4128b4 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt @@ -18,7 +18,7 @@ 17| 1| let mut generator = || { 18| 1| yield get_u32(is_true); 19| 1| return "foo"; - 20| 1| }; + 20| | }; 21| | 22| 1| match Pin::new(&mut generator).resume(()) { 23| 1| GeneratorState::Yielded(Ok(1)) => {} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 55a49548cb5e0..65eb1008dd83b 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt index 6e2f23ee77b8d..60a8d943f1fe8 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt @@ -8,7 +8,7 @@ 8| 1| let mut generator = || { 9| 1| yield 1; 10| 1| return "foo" - 11| 1| }; + 11| | }; 12| | 13| 1| match Pin::new(&mut generator).resume(()) { 14| 1| GeneratorState::Yielded(1) => {} @@ -24,7 +24,7 @@ 24| 1| yield 2; 25| 0| yield 3; 26| 0| return "foo" - 27| 0| }; + 27| | }; 28| | 29| 1| match Pin::new(&mut generator).resume(()) { 30| 1| GeneratorState::Yielded(1) => {} diff --git a/src/test/run-make-fulldeps/issue-26092/Makefile b/src/test/run-make-fulldeps/issue-26092/Makefile index 27631c31c4a06..885f45a022431 100644 --- a/src/test/run-make-fulldeps/issue-26092/Makefile +++ b/src/test/run-make-fulldeps/issue-26092/Makefile @@ -1,4 +1,6 @@ -include ../tools.mk +# This test ensures that rustc does not panic with `-o ""` option. + all: - $(RUSTC) -o "" blank.rs 2>&1 | $(CGREP) -i 'No such file or directory' + $(RUSTC) -o "" blank.rs 2>&1 | $(CGREP) -i 'panic' && exit 1 || exit 0 diff --git a/src/test/run-make-fulldeps/target-specs/Makefile b/src/test/run-make-fulldeps/target-specs/Makefile index dff7a966c9678..fb95ee5539acd 100644 --- a/src/test/run-make-fulldeps/target-specs/Makefile +++ b/src/test/run-make-fulldeps/target-specs/Makefile @@ -8,4 +8,4 @@ all: RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' - $(RUSTC) foo.rs --target=mismatching-data-layout + $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir index f02bccc4b2da5..ab4084c952a3d 100644 --- a/src/test/run-make/const_fn_mir/dump.mir +++ b/src/test/run-make/const_fn_mir/dump.mir @@ -33,7 +33,7 @@ fn main() -> () { _1 = foo() -> bb1; // scope 0 at main.rs:9:5: 9:10 // mir::Constant // + span: main.rs:9:5: 9:8 - // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn() -> i32 {foo}, val: Value(<ZST>) } } bb1: { diff --git a/src/test/run-make/issue-88756-default-output/Makefile b/src/test/run-make/issue-88756-default-output/Makefile new file mode 100644 index 0000000000000..cacbcbf3933a4 --- /dev/null +++ b/src/test/run-make/issue-88756-default-output/Makefile @@ -0,0 +1,4 @@ +-include ../../run-make-fulldeps/tools.mk + +all: + $(BARE_RUSTDOC) 2>&1 | sed -E 's@/nightly/|/beta/|/stable/|/1\.[0-9]+\.[0-9]+/@/$$CHANNEL/@g' | diff - output-default.stdout diff --git a/src/test/run-make/issue-88756-default-output/README.md b/src/test/run-make/issue-88756-default-output/README.md new file mode 100644 index 0000000000000..8cbfac4f7d2f1 --- /dev/null +++ b/src/test/run-make/issue-88756-default-output/README.md @@ -0,0 +1 @@ +This is a test to verify that the default behavior of `rustdoc` is printing out help output instead of erroring out (#88756). diff --git a/src/test/run-make/issue-88756-default-output/output-default.stdout b/src/test/run-make/issue-88756-default-output/output-default.stdout new file mode 100644 index 0000000000000..80cd08ee16734 --- /dev/null +++ b/src/test/run-make/issue-88756-default-output/output-default.stdout @@ -0,0 +1,197 @@ +rustdoc [options] <input> + +Options: + -h, --help show this help message + -V, --version print rustdoc's version + -v, --verbose use verbose output + -w, --output-format [html] + the output type to write + --output PATH Which directory to place the output. This option is + deprecated, use --out-dir instead. + -o, --out-dir PATH which directory to place the output + --crate-name NAME + specify the name of this crate + --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + Comma separated list of types of crates + for the compiler to emit + -L, --library-path DIR + directory to add to crate search path + --cfg pass a --cfg to rustc + --check-cfg pass a --check-cfg to rustc + --extern NAME[=PATH] + pass an --extern to rustc + --extern-html-root-url NAME=URL + base URL to use for dependencies; for example, + "std=/doc" links std::vec::Vec to + /doc/std/vec/struct.Vec.html + --extern-html-root-takes-precedence + give precedence to `--extern-html-root-url`, not + `html_root_url` + -C, --codegen OPT[=VALUE] + pass a codegen option to rustc + --document-private-items + document private items + --document-hidden-items + document items that have doc(hidden) + --test run code examples as tests + --test-args ARGS + arguments to pass to the test runner + --test-run-directory PATH + The working directory in which to run tests + --target TRIPLE target triple to document + --markdown-css FILES + CSS files to include via <link> in a rendered Markdown + file + --html-in-header FILES + files to include inline in the <head> section of a + rendered Markdown file or generated documentation + --html-before-content FILES + files to include inline between <body> and the content + of a rendered Markdown file or generated documentation + --html-after-content FILES + files to include inline between the content and + </body> of a rendered Markdown file or generated + documentation + --markdown-before-content FILES + files to include inline between <body> and the content + of a rendered Markdown file or generated documentation + --markdown-after-content FILES + files to include inline between the content and + </body> of a rendered Markdown file or generated + documentation + --markdown-playground-url URL + URL to send code snippets to + --markdown-no-toc + don't include table of contents + -e, --extend-css PATH + To add some CSS rules with a given file to generate + doc with your own theme. However, your theme might + break if the rustdoc's generated HTML changes, so be + careful! + -Z FLAG unstable / perma-unstable options (only on nightly + build) + --sysroot PATH Override the system root + --playground-url URL + URL to send code snippets to, may be reset by + --markdown-playground-url or + `#![doc(html_playground_url=...)]` + --display-doctest-warnings + show warnings that originate in doctests + --crate-version VERSION + crate version to print into documentation + --sort-modules-by-appearance + sort modules by where they appear in the program, + rather than alphabetically + --default-theme THEME + Set the default theme. THEME should be the theme name, + generally lowercase. If an unknown default theme is + specified, the builtin default is used. The set of + themes, and the rustdoc built-in default, are not + stable. + --default-setting SETTING[=VALUE] + Default value for a rustdoc setting (used when + "rustdoc-SETTING" is absent from web browser Local + Storage). If VALUE is not supplied, "true" is used. + Supported SETTINGs and VALUEs are not documented and + not stable. + --theme FILES additional themes which will be added to the generated + docs + --check-theme FILES + check if given theme is valid + --resource-suffix PATH + suffix to add to CSS and JavaScript files, e.g., + "light.css" will become "light-suffix.css" + --edition EDITION + edition to use when compiling rust code (default: + 2015) + --color auto|always|never + Configure coloring of output: + auto = colorize, if output goes to a tty (default); + always = always colorize output; + never = never colorize output + --error-format human|json|short + How errors and other messages are produced + --diagnostic-width WIDTH + Provide width of the output for truncated error + messages + --json CONFIG Configure the structure of JSON diagnostics + --disable-minification + Disable minification applied on JS files + -A, --allow LINT Set lint allowed + -W, --warn LINT Set lint warnings + --force-warn LINT + Set lint force-warn + -D, --deny LINT Set lint denied + -F, --forbid LINT Set lint forbidden + --cap-lints LEVEL + Set the most restrictive lint level. More restrictive + lints are capped at this level. By default, it is at + `forbid` level. + --index-page PATH + Markdown file to be used as index page + --enable-index-page + To enable generation of the index page + --static-root-path PATH + Path string to force loading static files from in + output pages. If not set, uses combinations of '../' + to reach the documentation root. + --disable-per-crate-search + disables generating the crate selector on the search + box + --persist-doctests PATH + Directory to persist doctest executables into + --show-coverage + calculate percentage of public items with + documentation + --enable-per-target-ignores + parse ignore-foo for ignoring doctests on a per-target + basis + --runtool The tool to run tests with when building for a different target than host + + --runtool-arg One (of possibly many) arguments to pass to the runtool + + --test-builder PATH + The rustc-like binary to use as the test builder + --check Run rustdoc checks + --generate-redirect-map + Generate JSON file at the top level instead of + generating HTML redirection files + --emit [unversioned-shared-resources,toolchain-shared-resources,invocation-specific] + Comma separated list of types of output for rustdoc to + emit + --no-run Compile doctests without running them + --show-type-layout + Include the memory layout of types in the docs + --nocapture Don't capture stdout and stderr of tests + --generate-link-to-definition + Make the identifiers in the HTML source code pages + navigable + --scrape-examples-output-path collect function call information and output at the given path + + --scrape-examples-target-crate collect function call information for functions from the target crate + + --scrape-tests Include test code when scraping examples + --with-examples path to function call information (for displaying examples in the documentation) + + --plugin-path DIR + removed, see issue #44136 + <https://github.com/rust-lang/rust/issues/44136> for + more information + --passes PASSES removed, see issue #44136 + <https://github.com/rust-lang/rust/issues/44136> for + more information + --plugins PLUGINS + removed, see issue #44136 + <https://github.com/rust-lang/rust/issues/44136> for + more information + --no-defaults removed, see issue #44136 + <https://github.com/rust-lang/rust/issues/44136> for + more information + -r, --input-format [rust] + removed, see issue #44136 + <https://github.com/rust-lang/rust/issues/44136> for + more information + + @path Read newline separated options from `path` + +More information available at https://doc.rust-lang.org/$CHANNEL/rustdoc/what-is-rustdoc.html diff --git a/src/test/run-make/issue-88756-default-output/x.rs b/src/test/run-make/issue-88756-default-output/x.rs new file mode 100644 index 0000000000000..5df7576133a68 --- /dev/null +++ b/src/test/run-make/issue-88756-default-output/x.rs @@ -0,0 +1 @@ +// nothing to see here diff --git a/src/test/run-make/native-link-modifier-bundle/Makefile b/src/test/run-make/native-link-modifier-bundle/Makefile index 723bb4689fe40..e4b0f74ac26ac 100644 --- a/src/test/run-make/native-link-modifier-bundle/Makefile +++ b/src/test/run-make/native-link-modifier-bundle/Makefile @@ -3,27 +3,31 @@ -include ../../run-make-fulldeps/tools.mk +# We're using the llvm-nm instead of the system nm to ensure it is compatible +# with the LLVM bitcode generated by rustc. +NM = "$(LLVM_BIN_DIR)"/llvm-nm + all: $(call NATIVE_STATICLIB,native-staticlib) # Build a staticlib and a rlib, the `native_func` symbol will be bundled into them $(RUSTC) bundled.rs --crate-type=staticlib --crate-type=rlib - nm $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func" - nm $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func" - nm $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func" - nm $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func" + $(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func" + $(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func" + $(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func" + $(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func" # Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it $(RUSTC) non-bundled.rs --crate-type=staticlib --crate-type=rlib - nm $(TMPDIR)/libnon_bundled.a | $(CGREP) -ve "T _*native_func" - nm $(TMPDIR)/libnon_bundled.a | $(CGREP) -e "U _*native_func" - nm $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -ve "T _*native_func" - nm $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -e "U _*native_func" + $(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -ve "T _*native_func" + $(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -e "U _*native_func" + $(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -ve "T _*native_func" + $(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -e "U _*native_func" # Build a cdylib, `native-staticlib` will not appear on the linker line because it was bundled previously # The cdylib will contain the `native_func` symbol in the end $(RUSTC) cdylib-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -ve '-l[" ]*native-staticlib' - nm $(call DYLIB,cdylib_bundled) | $(CGREP) -e "[Tt] _*native_func" + $(NM) $(call DYLIB,cdylib_bundled) | $(CGREP) -e "[Tt] _*native_func" # Build a cdylib, `native-staticlib` will appear on the linker line because it was not bundled previously # The cdylib will contain the `native_func` symbol in the end $(RUSTC) cdylib-non-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -e '-l[" ]*native-staticlib' - nm $(call DYLIB,cdylib_non_bundled) | $(CGREP) -e "[Tt] _*native_func" + $(NM) $(call DYLIB,cdylib_non_bundled) | $(CGREP) -e "[Tt] _*native_func" diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs index 998d202b11736..f29bc50e84c4e 100644 --- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs @@ -30,5 +30,5 @@ fn main() { assert_eq!(e as u32, 2); assert_eq!(FLAG.load(Ordering::SeqCst), 0); } - assert_eq!(FLAG.load(Ordering::SeqCst), 0); + assert_eq!(FLAG.load(Ordering::SeqCst), 1); } diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml index ddfb23a4f86ba..84b8bbd1b327f 100644 --- a/src/test/rustdoc-gui/anchors.goml +++ b/src/test/rustdoc-gui/anchors.goml @@ -28,7 +28,7 @@ move-cursor-to: "h2#implementations" assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"}) // Same thing with the impl block title. -move-cursor-to: "#impl" -assert-css: ("#impl a.anchor", {"color": "rgb(0, 0, 0)"}) +move-cursor-to: "#impl-HeavilyDocumentedStruct" +assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(0, 0, 0)"}) assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"}) diff --git a/src/test/rustdoc-gui/docblock-details.goml b/src/test/rustdoc-gui/docblock-details.goml new file mode 100644 index 0000000000000..2edbf1e4e2d8c --- /dev/null +++ b/src/test/rustdoc-gui/docblock-details.goml @@ -0,0 +1,23 @@ +// This ensures that the `<details>`/`<summary>` elements are displayed as expected. +goto: file://|DOC_PATH|/test_docs/details/struct.Details.html +show-text: true +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: + +// We first check that the headers in the `.top-doc` doc block still have their +// bottom border. +assert-text: (".top-doc .docblock > h3", "Hello") +assert-css: ( + ".top-doc .docblock > h3", + {"border-bottom": "1px solid rgb(221, 221, 221)"}, +) +// We now check that the `<summary>` doesn't have a bottom border and has the correct display. +assert-css: ( + ".top-doc .docblock summary h4", + {"border-bottom": "0px none rgb(221, 221, 221)"}, +) +// This allows to ensure that summary is on one line only! +assert-property: (".top-doc .docblock summary h4", {"offsetHeight": "33"}) +assert-css: (".top-doc .docblock summary h4", {"margin-top": "15px", "margin-bottom": "5px"}) +// So `33 + 15 + 5` == `53` +assert-property: (".top-doc .docblock summary", {"offsetHeight": "53"}) diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml index 8713bf65c8432..a5afb037d0fd5 100644 --- a/src/test/rustdoc-gui/escape-key.goml +++ b/src/test/rustdoc-gui/escape-key.goml @@ -3,6 +3,8 @@ goto: file://|DOC_PATH|/test_docs/index.html // First, we check that the search results are hidden when the Escape key is pressed. write: (".search-input", "test") +// To be SURE that the search will be run. +press-key: 'Enter' wait-for: "#search h1" // The search element is empty before the first search // Check that the currently displayed element is search. wait-for: "#alternative-display #search" @@ -21,17 +23,6 @@ wait-for: "#alternative-display #search" assert-attribute: ("#main-content", {"class": "content hidden"}) assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH) -// Now let's check that when the help popup is displayed and we press Escape, it doesn't -// hide the search results too. -click: "#help-button" -assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH]) -assert-attribute: ("#help", {"class": ""}) -press-key: "Escape" -wait-for: "#alternative-display #search" -assert-attribute: ("#help", {"class": "hidden"}) -assert-attribute: ("#main-content", {"class": "content hidden"}) -assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH]) - // Check that Escape hides the search results when a search result is focused. focus: ".search-input" assert: ".search-input:focus" @@ -39,7 +30,6 @@ press-key: "ArrowDown" assert-false: ".search-input:focus" assert: "#results a:focus" press-key: "Escape" -assert-attribute: ("#help", {"class": "hidden"}) wait-for: "#not-displayed #search" assert-false: "#alternative-display #search" assert-attribute: ("#main-content", {"class": "content"}) diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml index cf9caa2d5866a..a47a9c8a14c1f 100644 --- a/src/test/rustdoc-gui/headers-color.goml +++ b/src/test/rustdoc-gui/headers-color.goml @@ -23,9 +23,9 @@ assert-css: ( ALL, ) -goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo assert-css: ( - "#impl", + "#impl-Foo", {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"}, ) @@ -62,9 +62,9 @@ assert-css: ( ALL, ) -goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo assert-css: ( - "#impl", + "#impl-Foo", {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"}, ) @@ -99,8 +99,8 @@ assert-css: ( ALL, ) -goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl -assert-css: ("#impl", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"}) +goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo +assert-css: ("#impl-Foo", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"}) goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use assert-css: ( diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml index 67e97eb686e11..cc3dd61e99a7a 100644 --- a/src/test/rustdoc-gui/headings.goml +++ b/src/test/rustdoc-gui/headings.goml @@ -32,8 +32,8 @@ assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"}) assert-css: ("h2#implementations", {"font-size": "22px"}) assert-css: ("h2#implementations", {"border-bottom-width": "1px"}) -assert-css: ("#impl > h3.code-header", {"font-size": "18px"}) -assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"}) +assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"font-size": "18px"}) +assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"border-bottom-width": "0px"}) assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"}) assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"}) @@ -87,8 +87,8 @@ assert-css: ("h6#structy-prose-sub-heading", {"border-bottom-width": "0px"}) assert-css: ("h2#implementations", {"font-size": "22px"}) assert-css: ("h2#implementations", {"border-bottom-width": "1px"}) -assert-css: ("#impl > h3.code-header", {"font-size": "18px"}) -assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"}) +assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"font-size": "18px"}) +assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"border-bottom-width": "0px"}) assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"}) assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"}) @@ -129,8 +129,8 @@ assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"}) assert-css: ("h2#implementations", {"font-size": "22px"}) assert-css: ("h2#implementations", {"border-bottom-width": "1px"}) -assert-css: ("#impl > h3.code-header", {"font-size": "18px"}) -assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"}) +assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"font-size": "18px"}) +assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"border-bottom-width": "0px"}) assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"}) assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"}) assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"}) diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml index f29613f78b1b2..666a6e1253d9d 100644 --- a/src/test/rustdoc-gui/implementors.goml +++ b/src/test/rustdoc-gui/implementors.goml @@ -6,8 +6,8 @@ assert: "#implementors-list" assert-count: ("#implementors-list .impl", 2) // Now we check that both implementors have an anchor, an ID and a similar DOM. assert: ("#implementors-list .impl:nth-child(1) > a.anchor") -assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever"}) -assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever"}) +assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"}) +assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"}) assert: "#implementors-list .impl:nth-child(1) > .code-header.in-band" assert: ("#implementors-list .impl:nth-child(2) > a.anchor") @@ -16,8 +16,16 @@ assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band" goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html -compare-elements-position-near-false: ("#impl-EmptyTrait1", "#impl-EmptyTrait2", {"y": 30}) -compare-elements-position-near: ("#impl-EmptyTrait3 h3", "#impl-EmptyTrait3 .item-info", {"y": 30}) +compare-elements-position-near-false: ( + "#impl-EmptyTrait1-for-HasEmptyTraits", + "#impl-EmptyTrait2-for-HasEmptyTraits", + {"y": 30}, +) +compare-elements-position-near: ( + "#impl-EmptyTrait3-for-HasEmptyTraits h3", + "#impl-EmptyTrait3-for-HasEmptyTraits .item-info", + {"y": 30}, +) // Now check that re-exports work correctly. // There should be exactly one impl shown on both of these pages. diff --git a/src/test/rustdoc-gui/item-info-overflow.goml b/src/test/rustdoc-gui/item-info-overflow.goml index d6385e2acb8e6..b7095a3c5324d 100644 --- a/src/test/rustdoc-gui/item-info-overflow.goml +++ b/src/test/rustdoc-gui/item-info-overflow.goml @@ -15,14 +15,17 @@ assert-text: ( // Checking the "item-info" on an impl block as well: goto: file://|DOC_PATH|/lib2/struct.LongItemInfo2.html compare-elements-property: ( - "#impl-SimpleTrait .item-info", - "#impl-SimpleTrait + .docblock", + "#impl-SimpleTrait-for-LongItemInfo2 .item-info", + "#impl-SimpleTrait-for-LongItemInfo2 + .docblock", ["scrollWidth"], ) -assert-property: ("#impl-SimpleTrait .item-info", {"scrollWidth": "866"}) +assert-property: ( + "#impl-SimpleTrait-for-LongItemInfo2 .item-info", + {"scrollWidth": "866"}, +) // Just to be sure we're comparing the correct "item-info": assert-text: ( - "#impl-SimpleTrait .item-info", + "#impl-SimpleTrait-for-LongItemInfo2 .item-info", "Available on Android or Linux or Emscripten or DragonFly BSD", STARTS_WITH, ) diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml new file mode 100644 index 0000000000000..54f3790a76521 --- /dev/null +++ b/src/test/rustdoc-gui/pocket-menu.goml @@ -0,0 +1,77 @@ +// This test ensures that the "pocket menus" are working as expected. +goto: file://|DOC_PATH|/test_docs/index.html +// First we check that the help menu doesn't exist yet. +assert-false: "#help-button .popover" +// Then we display the help menu. +click: "#help-button" +assert: "#help-button .popover" +assert-css: ("#help-button .popover", {"display": "block"}) + +// Now we click somewhere else on the page to ensure it is handling the blur event +// correctly. +click: ".sidebar" +assert-css: ("#help-button .popover", {"display": "none"}) + +// Now we will check that we cannot have two "pocket menus" displayed at the same time. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "block"}) +click: "#settings-menu" +assert-css: ("#help-button .popover", {"display": "none"}) +assert-css: ("#settings-menu .popover", {"display": "block"}) + +// Now the other way. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "block"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + +// Now verify that clicking the help menu again closes it. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "none"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + +// We check the borders color now: + +// Ayu theme +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(92, 103, 115)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + +// Dark theme +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(210, 210, 210)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + +// Light theme +local-storage: { + "rustdoc-theme": "light", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(221, 221, 221)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml index d0b3175114cce..d645e23706161 100644 --- a/src/test/rustdoc-gui/search-filter.goml +++ b/src/test/rustdoc-gui/search-filter.goml @@ -2,6 +2,8 @@ goto: file://|DOC_PATH|/test_docs/index.html show-text: true write: (".search-input", "test") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" assert-text: ("#results .externcrate", "test_docs") diff --git a/src/test/rustdoc-gui/search-reexport.goml b/src/test/rustdoc-gui/search-reexport.goml index 557781d481092..5ef890d472b90 100644 --- a/src/test/rustdoc-gui/search-reexport.goml +++ b/src/test/rustdoc-gui/search-reexport.goml @@ -7,6 +7,8 @@ reload: assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;") assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"}) write: (".search-input", "TheStdReexport") +// To be SURE that the search will be run. +press-key: 'Enter' wait-for: "//a[@class='result-import']" assert-attribute: ( "//a[@class='result-import']", @@ -18,6 +20,8 @@ click: "//a[@class='result-import']" wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"}) // We now check that the alias is working as well on the reexport. +// To be SURE that the search will be run. +press-key: 'Enter' write: (".search-input", "AliasForTheStdReexport") wait-for: "//a[@class='result-import']" assert-text: ( diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml index 901634fe0e635..9a49ae2c6b853 100644 --- a/src/test/rustdoc-gui/search-result-color.goml +++ b/src/test/rustdoc-gui/search-result-color.goml @@ -89,6 +89,8 @@ show-text: true // We reload the page so the local storage settings are being used. reload: write: (".search-input", "thisisanalias") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" // Checking that the colors for the alias element are the ones expected. diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml index ff792eced703a..6295d7fae8907 100644 --- a/src/test/rustdoc-gui/search-result-display.goml +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -2,6 +2,8 @@ goto: file://|DOC_PATH|/test_docs/index.html size: (900, 1000) write: (".search-input", "test") +// To be SURE that the search will be run. +press-key: 'Enter' wait-for: "#search-settings" // The width is returned by "getComputedStyle" which returns the exact number instead of the // CSS rule which is "50%"... @@ -10,3 +12,31 @@ size: (600, 100) // As counter-intuitive as it may seem, in this width, the width is "100%", which is why // when computed it's larger. assert-css: (".search-results div.desc", {"width": "570px"}) + +// Check that the crate filter `<select>` is correctly handled when it goes to next line. +// To do so we need to update the length of one of its `<option>`. +size: (900, 900) + +// First we check the current width and position. +assert-css: ("#crate-search", {"width": "222px"}) +compare-elements-position-near: ( + "#crate-search", + "#search-settings .search-results-title", + {"y": 5}, +) + +// Then we update the text of one of the `<option>`. +text: ( + "#crate-search option", + "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa", +) + +// Then we compare again. +assert-css: ("#crate-search", {"width": "640px"}) +compare-elements-position-near-false: ( + "#crate-search", + "#search-settings .search-results-title", + {"y": 5}, +) +// And we check that the `<select>` isn't bigger than its container. +assert-css: ("#search", {"width": "640px"}) diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml index 8b50c5c5e1a5b..16ae10431acf2 100644 --- a/src/test/rustdoc-gui/search-result-keyword.goml +++ b/src/test/rustdoc-gui/search-result-keyword.goml @@ -1,6 +1,8 @@ // Checks that the "keyword" results have the expected text alongside them. goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "CookieMonster") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" // Note: The two next assert commands could be merged as one but readability would be diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml index 763927f9d0fe9..9d506c1519e6b 100644 --- a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -2,6 +2,8 @@ // First, try a search-by-name goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "Foo") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) @@ -22,6 +24,8 @@ wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"}) // Now try search-by-return goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "-> String") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) @@ -42,6 +46,8 @@ wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) // Try with a search-by-return with no results goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "-> Something") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) @@ -50,6 +56,8 @@ assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STA // Try with a search-by-parameter goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "usize pattern") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) @@ -58,6 +66,8 @@ assert-text: ("#titles > button:nth-of-type(1)", "In Function Parameters", START // Try with a search-by-parameter-and-return goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "pattern -> str") +// To be SURE that the search will be run. +press-key: 'Enter' // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index 237a4751a8d66..8a3365d3cc25e 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -20,6 +20,8 @@ wait-for-css: ("#settings", {"display": "none"}) // Let's click on it when the search results are displayed. focus: ".search-input" write: "test" +// To be SURE that the search will be run. +press-key: 'Enter' wait-for: "#alternative-display #search" click: "#settings-menu" wait-for-css: ("#settings", {"display": "block"}) @@ -121,6 +123,20 @@ local-storage: {"rustdoc-disable-shortcuts": "false"} click: ".setting-line:last-child .toggle .label" assert-local-storage: {"rustdoc-disable-shortcuts": "true"} +// Make sure that "Disable keyboard shortcuts" actually took effect. +press-key: "Escape" +press-key: "?" +assert-false: "#help-button .popover" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) + +// Now turn keyboard shortcuts back on, and see if they work. +click: ".setting-line:last-child .toggle .label" +assert-local-storage: {"rustdoc-disable-shortcuts": "false"} +press-key: "Escape" +press-key: "?" +wait-for-css: ("#help-button .popover", {"display": "block"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + // Now we go to the settings page to check that the CSS is loaded as expected. goto: file://|DOC_PATH|/settings.html wait-for: "#settings" diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml index 37a7c1662949d..1f20a0eaa9982 100644 --- a/src/test/rustdoc-gui/shortcuts.goml +++ b/src/test/rustdoc-gui/shortcuts.goml @@ -8,7 +8,6 @@ press-key: "Escape" assert-false: "input.search-input:focus" // We now check for the help popup. press-key: "?" -assert-css: ("#help", {"display": "flex"}) -assert-false: "#help.hidden" +assert-css: ("#help-button .popover", {"display": "block"}) press-key: "Escape" -assert-css: ("#help.hidden", {"display": "none"}) +assert-css: ("#help-button .popover", {"display": "none"}) diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml index 0066a38eaa540..fa322574fdec7 100644 --- a/src/test/rustdoc-gui/sidebar-source-code-display.goml +++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml @@ -17,3 +17,238 @@ assert-css: (".sidebar > *:not(#sidebar-toggle)", {"visibility": "hidden", "opac click: "#sidebar-toggle" // Because of the transition CSS, we check by using `wait-for-css` instead of `assert-css`. wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) + +// We now check that opening the sidebar and clicking a link will leave it open. +// The behavior here on desktop is different than the behavior on mobile, +// but since the sidebar doesn't fill the entire screen here, it makes sense to have the +// sidebar stay resident. +wait-for-css: (".sidebar", {"width": "300px"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} +click: ".sidebar a.selected" +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +wait-for-css: (".sidebar", {"width": "300px"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} + +// Now we check the display of the sidebar items. +show-text: true + +// First we start with the light theme. +local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: ( + "#source-sidebar details[open] > .files a.selected", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"}, +) +// Without hover or focus. +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"}) +// With focus. +focus: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"}) +focus: ".search-input" +// With hover. +move-cursor-to: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"}) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .files a:not(.selected)" +wait-for-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)" +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .folders > details > summary" +wait-for-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .folders > details > summary" +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"}, +) + +// Now with the dark theme. +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: ( + "#source-sidebar details[open] > .files > a.selected", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"}, +) +// Without hover or focus. +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"}) +// With focus. +focus: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"}) +focus: ".search-input" +// With hover. +move-cursor-to: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"}) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .files > a:not(.selected)", + {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .files a:not(.selected)" +wait-for-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)" +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .folders > details > summary" +wait-for-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .folders > details > summary" +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"}, +) + +// And finally with the ayu theme. +local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"} +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +assert-css: ( + "#source-sidebar details[open] > .files a.selected", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +// Without hover or focus. +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"}) +// With focus. +focus: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"}) +focus: ".search-input" +// With hover. +move-cursor-to: "#sidebar-toggle > button" +assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"}) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .files a:not(.selected)" +wait-for-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)" +assert-css: ( + "#source-sidebar details[open] > .files a:not(.selected)", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +// Without hover. +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"}, +) +// With focus. +focus: "#source-sidebar details[open] > .folders > details > summary" +wait-for-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) +focus: ".search-input" +// With hover. +move-cursor-to: "#source-sidebar details[open] > .folders > details > summary" +assert-css: ( + "#source-sidebar details[open] > .folders > details > summary", + {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"}, +) + +// Now checking on mobile devices. +size: (500, 700) +reload: +// Waiting for the sidebar to be displayed... +wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) + +// We now check it takes the full size of the display. +assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"}) +assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"}) + +// We now check the display of the toggle once the sidebar is expanded. +assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"}) +assert-css: ( + "#sidebar-toggle", + { + "border-top-width": "0px", + "border-right-width": "0px", + "border-left-width": "0px", + "border-bottom-width": "1px", + }, +) + +// We now check that the scroll position is kept when opening the sidebar. +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "0px"}) +// We scroll to line 117 to change the scroll position. +scroll-to: '//*[@id="117"]' +assert-window-property: {"pageYOffset": "2519"} +// Expanding the sidebar... +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "500px"}) +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "0px"}) +// The "scrollTop" property should be the same. +assert-window-property: {"pageYOffset": "2519"} + +// We now check that opening the sidebar and clicking a link will close it. +// The behavior here on mobile is different than the behavior on desktop, +// but common sense dictates that if you have a list of files that fills the entire screen, and +// you click one of them, you probably want to actually see the file's contents, and not just +// make it the current selection. +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} +click: ".sidebar a.selected" +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "false"} +// Resize back to desktop size, to check that the sidebar doesn't spontaneously open. +size: (1000, 1000) +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "false"} +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml index 724520bc399d0..86df478fa1dd2 100644 --- a/src/test/rustdoc-gui/sidebar-source-code.goml +++ b/src/test/rustdoc-gui/sidebar-source-code.goml @@ -18,8 +18,8 @@ assert: "nav.sidebar" // We now switch to mobile mode. size: (600, 600) -// We check that the sidebar has the expected width (0 and 1px for the border). -assert-css: ("nav.sidebar", {"width": "1px"}) +// We check that the sidebar has the expected width (0). +assert-css: ("nav.sidebar", {"width": "0px"}) // We expand the sidebar. click: "#sidebar-toggle" assert-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"}) diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml index b45512601f208..581f826a3d94d 100644 --- a/src/test/rustdoc-gui/source-code-page.goml +++ b/src/test/rustdoc-gui/source-code-page.goml @@ -34,19 +34,16 @@ assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH) click: "#sidebar-toggle" assert: ".source-sidebar-expanded" -// We check that the first entry of the sidebar is collapsed (which, for whatever reason, -// is number 2 and not 1...). -assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"}) -assert-text: ("#source-sidebar .name:nth-child(2)", "implementors") -// We also check its children are hidden too. -assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"}) +// We check that the first entry of the sidebar is collapsed +assert-property: ("#source-sidebar details:first-of-type", {"open": "false"}) +assert-text: ("#source-sidebar details:first-of-type > summary", "implementors") // We now click on it. -click: "#source-sidebar .name:nth-child(2)" -assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name expand"}) -// Checking that its children are displayed as well. -assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "block"}) +click: "#source-sidebar details:first-of-type > summary" +assert-property: ("#source-sidebar details:first-of-type", {"open": "true"}) // And now we collapse it again. -click: "#source-sidebar .name:nth-child(2)" -assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"}) -assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"}) +click: "#source-sidebar details:first-of-type > summary" +assert-property: ("#source-sidebar details:first-of-type", {"open": "false"}) + +// Check the spacing. +assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"}) diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs index b6fe9eb2565bd..aa2f78289bea2 100644 --- a/src/test/rustdoc-gui/src/test_docs/lib.rs +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -277,3 +277,15 @@ pub use macros::*; #[doc(alias = "AliasForTheStdReexport")] pub use ::std as TheStdReexport; + +pub mod details { + /// We check the appearance of the `<details>`/`<summary>` in here. + /// + /// ## Hello + /// + /// <details> + /// <summary><h4>I'm a summary</h4></summary> + /// <div>I'm the content of the details!</div> + /// </details> + pub struct Details; +} diff --git a/src/test/rustdoc-gui/toggle-click-deadspace.goml b/src/test/rustdoc-gui/toggle-click-deadspace.goml index 7bc3c56315784..4a328c9f9e06e 100644 --- a/src/test/rustdoc-gui/toggle-click-deadspace.goml +++ b/src/test/rustdoc-gui/toggle-click-deadspace.goml @@ -8,5 +8,5 @@ click: ".impl-items .rustdoc-toggle summary::before" // This is the position of assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""}) // Click the "Trait" part of "impl Trait" and verify it navigates. -click: "#impl-Trait h3 a:first-of-type" +click: "#impl-Trait-for-Foo h3 a:first-of-type" assert-text: (".fqn .in-band", "Trait lib2::Trait") diff --git a/src/test/rustdoc-json/assoc_items.rs b/src/test/rustdoc-json/assoc_items.rs new file mode 100644 index 0000000000000..2ee64c9f6eb99 --- /dev/null +++ b/src/test/rustdoc-json/assoc_items.rs @@ -0,0 +1,29 @@ +#![no_std] + +// @has assoc_items.json + +pub struct Simple; + +impl Simple { + // @has - "$.index[*][?(@.name=='CONSTANT')].kind" \"assoc_const\" + pub const CONSTANT: usize = 0; +} + +pub trait EasyToImpl { + // @has - "$.index[*][?(@.name=='ToDeclare')].kind" \"assoc_type\" + // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default" null + type ToDeclare; + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].kind" \"assoc_const\" + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" null + const AN_ATTRIBUTE: usize; +} + +impl EasyToImpl for Simple { + // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default.kind" \"primitive\" + // @has - "$.index[*][?(@.name=='ToDeclare')].inner.default.inner" \"usize\" + type ToDeclare = usize; + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.kind" \"primitive\" + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.type.inner" \"usize\" + // @has - "$.index[*][?(@.name=='AN_ATTRIBUTE')].inner.default" \"12\" + const AN_ATTRIBUTE: usize = 12; +} diff --git a/src/test/rustdoc-json/assoc_type.rs b/src/test/rustdoc-json/assoc_type.rs new file mode 100644 index 0000000000000..716bb3d2848cc --- /dev/null +++ b/src/test/rustdoc-json/assoc_type.rs @@ -0,0 +1,22 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98547>. + +// @has assoc_type.json +// @has - "$.index[*][?(@.name=='Trait')]" +// @has - "$.index[*][?(@.name=='AssocType')]" +// @has - "$.index[*][?(@.name=='S')]" +// @has - "$.index[*][?(@.name=='S2')]" + +pub trait Trait { + type AssocType; +} + +impl<T> Trait for T { + type AssocType = Self; +} + +pub struct S; + +/// Not needed for the #98547 ICE to occur, but added to maximize the chance of +/// getting an ICE in the future. See +/// <https://github.com/rust-lang/rust/pull/98548#discussion_r908219164> +pub struct S2; diff --git a/src/test/rustdoc-json/blanket_impls.rs b/src/test/rustdoc-json/blanket_impls.rs new file mode 100644 index 0000000000000..edf1a9fe2fcf9 --- /dev/null +++ b/src/test/rustdoc-json/blanket_impls.rs @@ -0,0 +1,9 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98658> + +#![no_std] + +// @has blanket_impls.json +// @has - "$.index[*][?(@.name=='Error')].kind" \"assoc_type\" +// @has - "$.index[*][?(@.name=='Error')].inner.default.kind" \"resolved_path\" +// @has - "$.index[*][?(@.name=='Error')].inner.default.inner.name" \"Infallible\" +pub struct ForBlanketTryFromImpl; diff --git a/src/test/rustdoc-json/doc_hidden_failure.rs b/src/test/rustdoc-json/doc_hidden_failure.rs new file mode 100644 index 0000000000000..5c4ccf996a54f --- /dev/null +++ b/src/test/rustdoc-json/doc_hidden_failure.rs @@ -0,0 +1,22 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98007>. + +#![feature(no_core)] +#![no_core] + +mod auto { + mod action_row { + pub struct ActionRowBuilder; + } + + #[doc(hidden)] + pub mod builders { + pub use super::action_row::ActionRowBuilder; + } +} + +// @count doc_hidden_failure.json "$.index[*][?(@.name=='builders')]" 2 +pub use auto::*; + +pub mod builders { + pub use crate::auto::builders::*; +} diff --git a/src/test/rustdoc-json/glob_import.rs b/src/test/rustdoc-json/glob_import.rs new file mode 100644 index 0000000000000..d7ac952d1bbc5 --- /dev/null +++ b/src/test/rustdoc-json/glob_import.rs @@ -0,0 +1,24 @@ +// This is a regression test for <https://github.com/rust-lang/rust/issues/98003>. + +#![feature(no_core)] +#![no_std] +#![no_core] + +// @has glob_import.json +// @has - "$.index[*][?(@.name=='glob')]" +// @has - "$.index[*][?(@.kind=='import')].inner.name" \"*\" + + +mod m1 { + pub fn f() {} +} +mod m2 { + pub fn f(_: u8) {} +} + +pub use m1::*; +pub use m2::*; + +pub mod glob { + pub use *; +} diff --git a/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs b/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs new file mode 100644 index 0000000000000..4a835673a596b --- /dev/null +++ b/src/test/rustdoc-json/reexport/auxiliary/pub-struct.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/src/test/rustdoc-json/reexport/glob_extern.rs b/src/test/rustdoc-json/reexport/glob_extern.rs index 831c185f6b136..ba1cfd8a0b577 100644 --- a/src/test/rustdoc-json/reexport/glob_extern.rs +++ b/src/test/rustdoc-json/reexport/glob_extern.rs @@ -3,15 +3,16 @@ #![no_core] #![feature(no_core)] -// @!has glob_extern.json "$.index[*][?(@.name=='mod1')]" +// @is glob_extern.json "$.index[*][?(@.name=='mod1')].kind" \"module\" +// @is glob_extern.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true" mod mod1 { extern "C" { - // @set public_fn_id = - "$.index[*][?(@.name=='public_fn')].id" + // @has - "$.index[*][?(@.name=='public_fn')].id" pub fn public_fn(); // @!has - "$.index[*][?(@.name=='private_fn')]" fn private_fn(); } } -// @has - "$.index[*][?(@.name=='glob_extern')].inner.items[*]" $public_fn_id +// @is - "$.index[*][?(@.kind=='import')].inner.glob" true pub use mod1::*; diff --git a/src/test/rustdoc-json/reexport/glob_private.rs b/src/test/rustdoc-json/reexport/glob_private.rs index e907de9236776..e6a44748c25fb 100644 --- a/src/test/rustdoc-json/reexport/glob_private.rs +++ b/src/test/rustdoc-json/reexport/glob_private.rs @@ -3,9 +3,11 @@ #![no_core] #![feature(no_core)] -// @!has glob_private.json "$.index[*][?(@.name=='mod1')]" +// @is glob_private.json "$.index[*][?(@.name=='mod1')].kind" \"module\" +// @is glob_private.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true" mod mod1 { - // @!has - "$.index[*][?(@.name=='mod2')]" + // @is - "$.index[*][?(@.name=='mod2')].kind" \"module\" + // @is - "$.index[*][?(@.name=='mod2')].inner.is_stripped" "true" mod mod2 { // @set m2pub_id = - "$.index[*][?(@.name=='Mod2Public')].id" pub struct Mod2Public; @@ -13,15 +15,18 @@ mod mod1 { // @!has - "$.index[*][?(@.name=='Mod2Private')]" struct Mod2Private; } + + // @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')]" pub use self::mod2::*; // @set m1pub_id = - "$.index[*][?(@.name=='Mod1Public')].id" pub struct Mod1Public; - // @!has - "$.index[*][?(@.name=='Mod1Private')]" struct Mod1Private; } + +// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')]" pub use mod1::*; -// @has - "$.index[*][?(@.name=='glob_private')].inner.items[*]" $m2pub_id -// @has - "$.index[*][?(@.name=='glob_private')].inner.items[*]" $m1pub_id +// @has - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id +// @has - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod.rs b/src/test/rustdoc-json/reexport/in_root_and_mod.rs index e3cecbdd7ff2f..7bf10a9868616 100644 --- a/src/test/rustdoc-json/reexport/in_root_and_mod.rs +++ b/src/test/rustdoc-json/reexport/in_root_and_mod.rs @@ -1,15 +1,17 @@ #![feature(no_core)] #![no_core] +// @is in_root_and_mod.json "$.index[*][?(@.name=='foo')].kind" \"module\" +// @is in_root_and_mod.json "$.index[*][?(@.name=='foo')].inner.is_stripped" "true" mod foo { - // @set foo_id = in_root_and_mod.json "$.index[*][?(@.name=='Foo')].id" + // @has - "$.index[*][?(@.name=='Foo')]" pub struct Foo; } -// @has - "$.index[*][?(@.name=='in_root_and_mod')].inner.items[*]" $foo_id +// @has - "$.index[*][?(@.kind=='import' && @.inner.source=='foo::Foo')]" pub use foo::Foo; pub mod bar { - // @has - "$.index[*][?(@.name=='bar')].inner.items[*]" $foo_id + // @has - "$.index[*][?(@.kind=='import' && @.inner.source=='crate::foo::Foo')]" pub use crate::foo::Foo; } diff --git a/src/test/rustdoc-json/reexport/private_twice_one_inline.rs b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs new file mode 100644 index 0000000000000..327b0f45fdd54 --- /dev/null +++ b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs @@ -0,0 +1,18 @@ +// aux-build:pub-struct.rs + +// Test for the ICE in rust/83057 +// Am external type re-exported with different attributes shouldn't cause an error + +#![no_core] +#![feature(no_core)] + +extern crate pub_struct as foo; + +#[doc(inline)] +pub use foo::Foo; + +pub mod bar { + pub use foo::Foo; +} + +// @count private_twice_one_inline.json "$.index[*][?(@.kind=='import')]" 2 diff --git a/src/test/rustdoc-json/reexport/private_two_names.rs b/src/test/rustdoc-json/reexport/private_two_names.rs new file mode 100644 index 0000000000000..36d6a50d385a2 --- /dev/null +++ b/src/test/rustdoc-json/reexport/private_two_names.rs @@ -0,0 +1,17 @@ +// Test for the ICE in rust/83720 +// A pub-in-private type re-exported under two different names shouldn't cause an error + +#![no_core] +#![feature(no_core)] + +// @is private_two_names.json "$.index[*][?(@.name=='style')].kind" \"module\" +// @is private_two_names.json "$.index[*][?(@.name=='style')].inner.is_stripped" "true" +mod style { + // @has - "$.index[*](?(@.name=='Color'))" + pub struct Color; +} + +// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')]" +pub use style::Color; +// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')]" +pub use style::Color as Colour; diff --git a/src/test/rustdoc-json/reexport/rename_private.rs b/src/test/rustdoc-json/reexport/rename_private.rs index fb8296f23374a..2476399bd561c 100644 --- a/src/test/rustdoc-json/reexport/rename_private.rs +++ b/src/test/rustdoc-json/reexport/rename_private.rs @@ -2,13 +2,13 @@ #![no_core] #![feature(no_core)] -// @!has rename_private.json "$.index[*][?(@.name=='inner')]" + +// @is rename_private.json "$.index[*][?(@.name=='inner')].kind" \"module\" +// @is rename_private.json "$.index[*][?(@.name=='inner')].inner.is_stripped" "true" mod inner { - // @!has - "$.index[*][?(@.name=='Public')]" + // @has - "$.index[*][?(@.name=='Public')]" pub struct Public; } -// @set newname_id = - "$.index[*][?(@.name=='NewName')].id" -// @is - "$.index[*][?(@.name=='NewName')].kind" \"struct\" -// @has - "$.index[*][?(@.name=='rename_private')].inner.items[*]" $newname_id +// @is - "$.index[*][?(@.kind=='import')].inner.name" \"NewName\" pub use inner::Public as NewName; diff --git a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs index fd6ac8372d976..eedddd6a7bb48 100644 --- a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs +++ b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs @@ -1,15 +1,13 @@ -// Regression test for https://github.com/rust-lang/rust/issues/97432. +// Regression test for <https://github.com/rust-lang/rust/issues/97432>. #![feature(no_core)] #![no_std] #![no_core] // @has same_type_reexported_more_than_once.json -// @set trait_id = - "$.index[*][?(@.name=='Trait')].id" -// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $trait_id +// @has - "$.index[*][?(@.name=='Trait')]" pub use inner::Trait; -// @set reexport_id = - "$.index[*][?(@.name=='Reexport')].id" -// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id +// @has - "$.index[*].inner[?(@.name=='Reexport')].id" pub use inner::Trait as Reexport; mod inner { diff --git a/src/test/rustdoc-json/reexport/simple_private.rs b/src/test/rustdoc-json/reexport/simple_private.rs index 658b121e6ce97..5ec13e403aef6 100644 --- a/src/test/rustdoc-json/reexport/simple_private.rs +++ b/src/test/rustdoc-json/reexport/simple_private.rs @@ -1,13 +1,15 @@ // edition:2018 - #![no_core] #![feature(no_core)] -// @!has simple_private.json "$.index[*][?(@.name=='inner')]" +// @is simple_private.json "$.index[*][?(@.name=='inner')].kind" \"module\" +// @is simple_private.json "$.index[*][?(@.name=='inner')].inner.is_stripped" "true" mod inner { // @set pub_id = - "$.index[*][?(@.name=='Public')].id" pub struct Public; } -// @has - "$.index[*][?(@.name=='simple_private')].inner.items[*]" $pub_id +// @is - "$.index[*][?(@.kind=='import')].inner.name" \"Public\" pub use inner::Public; + +// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id diff --git a/src/test/rustdoc-json/return_private.rs b/src/test/rustdoc-json/return_private.rs new file mode 100644 index 0000000000000..6b324d0090a15 --- /dev/null +++ b/src/test/rustdoc-json/return_private.rs @@ -0,0 +1,15 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/96161>. +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +mod secret { + pub struct Secret; +} + +// @is return_private.json "$.index[*][?(@.name=='get_secret')].kind" \"function\" +// @is return_private.json "$.index[*][?(@.name=='get_secret')].inner.decl.output.inner.name" \"secret::Secret\" +pub fn get_secret() -> secret::Secret { + secret::Secret +} diff --git a/src/test/rustdoc-json/stripped_modules.rs b/src/test/rustdoc-json/stripped_modules.rs new file mode 100644 index 0000000000000..91f9f02ad7b47 --- /dev/null +++ b/src/test/rustdoc-json/stripped_modules.rs @@ -0,0 +1,21 @@ +#![no_core] +#![feature(no_core)] + +// @!has stripped_modules.json "$.index[*][?(@.name=='no_pub_inner')]" +mod no_pub_inner { + fn priv_inner() {} +} + +// @!has - "$.index[*][?(@.name=='pub_inner_unreachable')]" +mod pub_inner_unreachable { + // @!has - "$.index[*][?(@.name=='pub_inner_1')]" + pub fn pub_inner_1() {} +} + +// @has - "$.index[*][?(@.name=='pub_inner_reachable')]" +mod pub_inner_reachable { + // @has - "$.index[*][?(@.name=='pub_inner_2')]" + pub fn pub_inner_2() {} +} + +pub use pub_inner_reachable::pub_inner_2; diff --git a/src/test/rustdoc-ui/c-help.rs b/src/test/rustdoc-ui/c-help.rs new file mode 100644 index 0000000000000..e166edf8b619c --- /dev/null +++ b/src/test/rustdoc-ui/c-help.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Chelp +// check-stdout +// regex-error-pattern: -C\s+incremental + +pub struct Foo; diff --git a/src/test/rustdoc-ui/c-help.stdout b/src/test/rustdoc-ui/c-help.stdout new file mode 100644 index 0000000000000..75b2e2a2a43f4 --- /dev/null +++ b/src/test/rustdoc-ui/c-help.stdout @@ -0,0 +1,51 @@ + -C ar=val -- this option is deprecated and does nothing + -C code-model=val -- choose the code model to use (`rustc --print code-models` for details) + -C codegen-units=val -- divide crate into N units to optimize in parallel + -C control-flow-guard=val -- use Windows Control Flow Guard (default: no) + -C debug-assertions=val -- explicitly enable the `cfg(debug_assertions)` directive + -C debuginfo=val -- debug info emission level (0 = no debug info, 1 = line tables only, 2 = full debug info with variable and type information; default: 0) + -C default-linker-libraries=val -- allow the linker to link its default libraries (default: no) + -C embed-bitcode=val -- emit bitcode in rlibs (default: yes) + -C extra-filename=val -- extra data to put in each output filename + -C force-frame-pointers=val -- force use of the frame pointers + -C force-unwind-tables=val -- force use of unwind tables + -C incremental=val -- enable incremental compilation + -C inline-threshold=val -- set the threshold for inlining a function + -C instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are: + `=all` (implicit value) + `=except-unused-generics` + `=except-unused-functions` + `=off` (default) + -C link-arg=val -- a single extra argument to append to the linker invocation (can be used several times) + -C link-args=val -- extra arguments to append to the linker invocation (space separated) + -C link-dead-code=val -- keep dead code at link time (useful for code coverage) (default: no) + -C link-self-contained=val -- control whether to link Rust provided C objects/libraries or rely + on C toolchain installed in the system + -C linker=val -- system linker to link outputs with + -C linker-flavor=val -- linker flavor + -C linker-plugin-lto=val -- generate build artifacts that are compatible with linker-based LTO + -C llvm-args=val -- a list of arguments to pass to LLVM (space separated) + -C lto=val -- perform LLVM link-time optimizations + -C metadata=val -- metadata to mangle symbol names with + -C no-prepopulate-passes=val -- give an empty list of passes to the pass manager + -C no-redzone=val -- disable the use of the redzone + -C no-stack-check=val -- this option is deprecated and does nothing + -C no-vectorize-loops=val -- disable loop vectorization optimization passes + -C no-vectorize-slp=val -- disable LLVM's SLP vectorization pass + -C opt-level=val -- optimization level (0-3, s, or z; default: 0) + -C overflow-checks=val -- use overflow checks for integer arithmetic + -C panic=val -- panic strategy to compile crate with + -C passes=val -- a list of extra LLVM passes to run (space separated) + -C prefer-dynamic=val -- prefer dynamic linking to static linking (default: no) + -C profile-generate=val -- compile the program with profiling instrumentation + -C profile-use=val -- use the given `.profdata` file for profile-guided optimization + -C relocation-model=val -- control generation of position-independent code (PIC) (`rustc --print relocation-models` for details) + -C remark=val -- print remarks for these optimization passes (space separated, or "all") + -C rpath=val -- set rpath values in libs/exes (default: no) + -C save-temps=val -- save all temporary output files during compilation (default: no) + -C soft-float=val -- use soft float ABI (*eabihf targets only) (default: no) + -C split-debuginfo=val -- how to handle split-debuginfo, a platform-specific option + -C strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) + -C symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') + -C target-cpu=val -- select target processor (`rustc --print target-cpus` for details) + -C target-feature=val -- target specific attributes. (`rustc --print target-features` for details). This feature is unsafe. diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr index 821e6b99f7b8f..5025b0b0ca825 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr @@ -16,7 +16,7 @@ error: missing documentation for a struct --> $DIR/deny-missing-docs-crate.rs:3:1 | LL | pub struct Foo; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/rustdoc-ui/diagnostic-width.rs b/src/test/rustdoc-ui/diagnostic-width.rs new file mode 100644 index 0000000000000..61961d5ec710e --- /dev/null +++ b/src/test/rustdoc-ui/diagnostic-width.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zunstable-options --diagnostic-width=10 +#![deny(rustdoc::bare_urls)] + +/// This is a long line that contains a http://link.com +pub struct Foo; //~^ ERROR diff --git a/src/test/rustdoc-ui/diagnostic-width.stderr b/src/test/rustdoc-ui/diagnostic-width.stderr new file mode 100644 index 0000000000000..fed049d2b37bc --- /dev/null +++ b/src/test/rustdoc-ui/diagnostic-width.stderr @@ -0,0 +1,15 @@ +error: this URL is not a hyperlink + --> $DIR/diagnostic-width.rs:4:41 + | +LL | ... a http://link.com + | ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>` + | +note: the lint level is defined here + --> $DIR/diagnostic-width.rs:2:9 + | +LL | ...ny(rustdoc::bare_url... + | ^^^^^^^^^^^^^^^^^^ + = note: bare URLs are not automatically turned into clickable links + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs new file mode 100644 index 0000000000000..a30472ac56b24 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.rs @@ -0,0 +1,10 @@ +// compile-flags:--test --test-args=--test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +/// ``` +/// #![deprecated(since = "5.2", note = "foo was rarely used. \ +/// Users should instead use bar")] +/// ``` +pub fn f() {} diff --git a/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout new file mode 100644 index 0000000000000..07a4f657dea6a --- /dev/null +++ b/src/test/rustdoc-ui/doctest-multiline-crate-attribute.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doctest-multiline-crate-attribute.rs - f (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/invalid-doc-attr.stderr b/src/test/rustdoc-ui/invalid-doc-attr.stderr index 55006b2087eb0..a4fa3817905c7 100644 --- a/src/test/rustdoc-ui/invalid-doc-attr.stderr +++ b/src/test/rustdoc-ui/invalid-doc-attr.stderr @@ -12,7 +12,7 @@ LL | #![deny(warnings)] = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] @@ -29,7 +29,7 @@ LL | pub fn foo() {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information error: this attribute can only be applied at the crate level --> $DIR/invalid-doc-attr.rs:15:12 @@ -39,7 +39,7 @@ LL | #![doc(test(no_crate_inject))] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information error: conflicting doc inlining attributes --> $DIR/invalid-doc-attr.rs:28:7 @@ -59,7 +59,7 @@ LL | #[doc(test(no_crate_inject))] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information error: this attribute can only be applied to a `use` item --> $DIR/invalid-doc-attr.rs:22:11 @@ -72,7 +72,7 @@ LL | pub fn baz() {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information error: aborting due to 6 previous errors diff --git a/src/test/rustdoc-ui/issue-79467.rs b/src/test/rustdoc-ui/issue-79467.rs new file mode 100644 index 0000000000000..eb0b9b380714e --- /dev/null +++ b/src/test/rustdoc-ui/issue-79467.rs @@ -0,0 +1,8 @@ +fn g() +where + 'static: 'static, + dyn 'static: 'static + Copy, //~ ERROR at least one trait is required for an object type +{ +} + +fn main() {} diff --git a/src/test/rustdoc-ui/issue-79467.stderr b/src/test/rustdoc-ui/issue-79467.stderr new file mode 100644 index 0000000000000..561513a432bb5 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79467.stderr @@ -0,0 +1,9 @@ +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-79467.rs:4:5 + | +LL | dyn 'static: 'static + Copy, + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0224`. diff --git a/src/test/rustdoc-ui/issue-79494.rs b/src/test/rustdoc-ui/issue-79494.rs new file mode 100644 index 0000000000000..fc39424b793f6 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79494.rs @@ -0,0 +1,5 @@ +// only-x86_64-unknown-linux-gnu + +#![feature(const_transmute)] + +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types diff --git a/src/test/rustdoc-ui/issue-79494.stderr b/src/test/rustdoc-ui/issue-79494.stderr new file mode 100644 index 0000000000000..7ed5ed3824716 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79494.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/issue-79494.rs:5:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (64 bits) + = note: target type: `&[u8]` (128 bits) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.rs b/src/test/rustdoc-ui/issue-83883-describe-lints.rs index a261b782d4859..0474d6c143e92 100644 --- a/src/test/rustdoc-ui/issue-83883-describe-lints.rs +++ b/src/test/rustdoc-ui/issue-83883-describe-lints.rs @@ -1,8 +1,10 @@ // compile-flags: -W help // check-pass +// check-stdout +// error-pattern:Lint checks provided +// error-pattern:rustdoc::broken-intra-doc-links // // ignore-tidy-linelength // // normalize-stdout-test: "( +name default meaning\n +---- ------- -------\n)?( *[[:word:]:-]+ (allow |warn |deny |forbid ) [^\n]+\n)+" -> " $$NAMES $$LEVELS $$MEANINGS" // normalize-stdout-test: " +name sub-lints\n +---- ---------\n( *[[:word:]:-]+ [^\n]+\n)+" -> " $$NAMES $$SUB_LINTS" -// normalize-stdout-test: " +rustdoc::all( (rustdoc::[[:word:]-]+, )*rustdoc::[[:word:]-]+)?" -> " rustdoc::all $$GROUPS$4" diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.stdout b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout index 651faf5761f18..bbf66a31583d2 100644 --- a/src/test/rustdoc-ui/issue-83883-describe-lints.stdout +++ b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout @@ -20,6 +20,5 @@ Lint checks provided by plugins loaded by this crate: Lint groups provided by plugins loaded by this crate: - rustdoc::all $GROUPS - + $NAMES $SUB_LINTS diff --git a/src/test/rustdoc-ui/issue-98690.rs b/src/test/rustdoc-ui/issue-98690.rs new file mode 100644 index 0000000000000..fe9bd87ab28e6 --- /dev/null +++ b/src/test/rustdoc-ui/issue-98690.rs @@ -0,0 +1,10 @@ +// compile-flags: --test --persist-doctests /../../ -Z unstable-options +// failure-status: 101 +// only-linux + +#![crate_name = "foo"] + +//! ```rust +//! use foo::dummy; +//! dummy(); +//! ``` diff --git a/src/test/rustdoc-ui/issue-98690.stderr b/src/test/rustdoc-ui/issue-98690.stderr new file mode 100644 index 0000000000000..47d94f99a4563 --- /dev/null +++ b/src/test/rustdoc-ui/issue-98690.stderr @@ -0,0 +1 @@ +Couldn't create directory for doctest executables: Permission denied (os error 13) diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr index 3715797854281..9e51ecd2ba017 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -1,9 +1,8 @@ error: missing code example in this documentation --> $DIR/lint-missing-doc-code-example.rs:19:1 | -LL | / pub mod module1 { -LL | | } - | |_^ +LL | pub mod module1 { + | ^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-missing-doc-code-example.rs:2:9 diff --git a/src/test/rustdoc-ui/z-help.rs b/src/test/rustdoc-ui/z-help.rs new file mode 100644 index 0000000000000..c7cf841b93707 --- /dev/null +++ b/src/test/rustdoc-ui/z-help.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Zhelp +// check-stdout +// regex-error-pattern: -Z\s+self-profile + +pub struct Foo; diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout new file mode 100644 index 0000000000000..7296b35788a9d --- /dev/null +++ b/src/test/rustdoc-ui/z-help.stdout @@ -0,0 +1,195 @@ + -Z allow-features=val -- only allow the listed language features to be enabled in code (space separated) + -Z always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no) + -Z assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no) + -Z asm-comments=val -- generate comments into the assembly (may change behavior) (default: no) + -Z assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`. + -Z binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no) + -Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64 + -Z cf-protection=val -- instrument control-flow architecture protection + -Z cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use + -Z chalk=val -- enable the experimental Chalk-based trait solving engine + -Z codegen-backend=val -- the backend to use + -Z combine-cgu=val -- combine CGUs into a single one + -Z crate-attr=val -- inject the given attribute in the crate + -Z debug-info-for-profiling=val -- emit discriminators and other data necessary for AutoFDO + -Z debug-macros=val -- emit line numbers debug info inside macros (default: no) + -Z deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes) + -Z dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no) + -Z dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no) + -Z dlltool=val -- import library generation tool (windows-gnu only) + -Z dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no) + -Z drop-tracking=val -- enables drop tracking in generators (default: no) + -Z dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no) + -Z dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no) + -Z dump-drop-tracking-cfg=val -- dump drop-tracking control-flow graph as a `.dot` file (default: no) + -Z dump-mir=val -- dump MIR state to file. + `val` is used to select which passes and functions to dump. For example: + `all` matches all passes and functions, + `foo` matches all passes for functions whose name contains 'foo', + `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', + `foo | bar` all passes for function names containing 'foo' or 'bar'. + -Z dump-mir-dataflow=val -- in addition to `.mir` files, create graphviz `.dot` files with dataflow results (default: no) + -Z dump-mir-dir=val -- the directory the MIR is dumped into (default: `mir_dump`) + -Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no) + -Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no) + -Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans. + -Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform) + -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) + -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (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 + -Z future-incompat-test=val -- forces all lints to be future incompatible, used for internal testing (default: no) + -Z gcc-ld=val -- implementation of ld used by cc + -Z graphviz-dark-mode=val -- use dark-themed colors in graphviz output (default: no) + -Z graphviz-font=val -- use the given `fontname` in graphviz output; can be overridden by setting environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`) + -Z hir-stats=val -- print some statistics about AST and HIR (default: no) + -Z human-readable-cgu-names=val -- generate human-readable, predictable names for codegen units (default: no) + -Z identify-regions=val -- display unnamed regions as `'<id>`, using a non-ident unique id (default: no) + -Z incremental-ignore-spans=val -- ignore spans during ICH computation -- used for testing (default: no) + -Z incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no) + -Z incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no) + -Z incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no) + -Z inline-mir=val -- enable MIR inlining (default: no) + -Z inline-mir-threshold=val -- a default MIR inlining threshold (default: 50) + -Z inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100) + -Z inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs + -Z input-stats=val -- gather statistics about the input (default: no) + -Z instrument-coverage=val -- instrument the generated code to support LLVM source-based code coverage reports (note, the compiler build config must include `profiler = true`); implies `-C symbol-mangling-version=v0`. Optional values are: + `=all` (implicit value) + `=except-unused-generics` + `=except-unused-functions` + `=off` (default) + -Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no) + -Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no) + -Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes) + -Z link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no) + -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) + -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no) + -Z location-detail=val -- comma separated list of location details to be tracked when using caller_location valid options are `file`, `line`, and `column` (default: all) + -Z ls=val -- list the symbols defined by a library crate (default: no) + -Z macro-backtrace=val -- show macro backtraces (default: no) + -Z merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name + -Z meta-stats=val -- gather metadata statistics (default: no) + -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no) + -Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual. + -Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds) + -Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted + -Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes) + -Z new-llvm-pass-manager=val -- use new LLVM pass manager (default: no) + -Z nll-facts=val -- dump facts from NLL analysis into side files (default: no) + -Z nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`) + -Z no-analysis=val -- parse and expand the source, but run no analysis + -Z no-codegen=val -- run all passes except codegen; no output + -Z no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups + -Z no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints + -Z no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests + -Z no-link=val -- compile without linking + -Z no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO) + -Z no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used + -Z no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate + -Z normalize-docs=val -- normalize associated items in rustdoc when generating documentation + -Z oom=val -- panic strategy for out-of-memory handling + -Z osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no) + -Z diagnostic-width=val -- set the current output width for diagnostic truncation + -Z panic-abort-tests=val -- support compiling tests with panic=abort (default: no) + -Z panic-in-drop=val -- panic strategy for panics in drops + -Z parse-only=val -- parse only; do not compile, assemble, or link (default: no) + -Z perf-stats=val -- print some performance-related statistics (default: no) + -Z pick-stable-methods-before-any-unstable=val -- try to pick stable methods first before picking any unstable methods (default: yes) + -Z plt=val -- whether to use the PLT when calling into shared libraries; + only has effect for PIC code on systems with ELF binaries + (default: PLT is disabled if full relro is enabled) + -Z polonius=val -- enable polonius-based borrow-checker (default: no) + -Z polymorphize=val -- perform polymorphization analysis + -Z pre-link-arg=val -- a single extra argument to prepend the linker invocation (can be used several times) + -Z pre-link-args=val -- extra arguments to prepend to the linker invocation (space separated) + -Z precise-enum-drop-elaboration=val -- use a more precise version of drop elaboration for matches on enums (default: yes). This results in better codegen, but has caused miscompilations on some tier 2 platforms. See #77382 and #74551. + -Z print-fuel=val -- make rustc print the total optimization fuel used by a crate + -Z print-llvm-passes=val -- print the LLVM optimization passes being run (default: no) + -Z print-mono-items=val -- print the result of the monomorphization collection pass + -Z print-type-sizes=val -- print layout information for each type encountered (default: no) + -Z proc-macro-backtrace=val -- show backtraces for panics during proc-macro execution (default: no) + -Z profile=val -- insert profiling code (default: no) + -Z profile-closures=val -- profile size of closures + -Z profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path) + -Z profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`) + -Z profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO) + -Z query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no) + -Z randomize-layout=val -- randomize the layout of types (default: no) + -Z layout-seed=val -- seed layout randomization + -Z relax-elf-relocations=val -- whether ELF relocations can be relaxed + -Z relro-level=val -- choose which RELRO level to use + -Z remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix + -Z simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes + -Z report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no) + -Z sanitizer=val -- use a sanitizer + -Z sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer + -Z sanitizer-recover=val -- enable recovery for selected sanitizers + -Z saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes) + -Z save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no) + -Z self-profile=val -- run the self profiler and output the raw event data + -Z self-profile-events=val -- specify the events recorded by the self profiler; + for example: `-Z self-profile-events=default,query-keys` + all options: none, all, default, generic-activity, query-provider, query-cache-hit + query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes + -Z self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of: + `wall-time` (monotonic clock, i.e. `std::time::Instant`) + `instructions:u` (retired instructions, userspace-only) + `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy) + -Z share-generics=val -- make the current crate share its generic instantiations + -Z show-span=val -- show spans for compiler debugging (expr|pat|ty) + -Z span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span` + -Z span-free-formats=val -- exclude spans when debug-printing compiler state (default: no) + -Z src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`) + -Z stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details) + -Z strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB + -Z strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`) + -Z split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) + (default: `split`) + + `split`: sections which do not require relocation are written into a DWARF object (`.dwo`) + file which is ignored by the linker + `single`: sections which do not require relocation are written into object file but ignored + by the linker + -Z split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF + -Z symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0') + -Z teach=val -- show extended diagnostic help (default: no) + -Z temps-dir=val -- the directory the intermediate files are written to + -Z translate-lang=val -- language identifier for diagnostic output + -Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation) + -Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics + -Z tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details) + -Z thinlto=val -- enable ThinLTO when possible + -Z thir-unsafeck=val -- use the THIR unsafety checker (default: no) + -Z threads=val -- use a thread pool with N threads + -Z time=val -- measure time of rustc processes (default: no) + -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 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) + -Z translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes) + -Z trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes) + -Z treat-err-as-bug=val -- treat error number `val` that occurs as bug + -Z trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items + -Z ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no) + -Z uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16) + -Z unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no) + -Z unpretty=val -- present the input source, unstable (and less-pretty) variants; + `normal`, `identified`, + `expanded`, `expanded,identified`, + `expanded,hygiene` (with internal representations), + `ast-tree` (raw AST before expansion), + `ast-tree,expanded` (raw AST after expansion), + `hir` (the HIR), `hir,identified`, + `hir,typed` (HIR with types for each node), + `hir-tree` (dump the raw HIR), + `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR) + -Z unsound-mir-opts=val -- enable unsound and buggy MIR optimizations (default: no) + -Z unstable-options=val -- adds unstable command line options to rustc interface (default: no) + -Z use-ctors-section=val -- use legacy .ctors section for initializers rather than .init_array + -Z validate-mir=val -- validate MIR after each transformation + -Z verbose=val -- in general, enable more debug printouts (default: no) + -Z verify-llvm-ir=val -- verify LLVM IR (default: no) + -Z virtual-function-elimination=val -- enables dead virtual function elimination optimization. Requires `-Clto[=[fat,yes]]` + -Z wasi-exec-model=val -- whether to build a wasi command or reactor diff --git a/src/test/rustdoc/anchors.no_const_anchor.html b/src/test/rustdoc/anchors.no_const_anchor.html new file mode 100644 index 0000000000000..98f47e53038a9 --- /dev/null +++ b/src/test/rustdoc/anchors.no_const_anchor.html @@ -0,0 +1 @@ +<div id="associatedconstant.YOLO" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#16">source</a></div><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></div> diff --git a/src/test/rustdoc/anchors.no_const_anchor2.html b/src/test/rustdoc/anchors.no_const_anchor2.html new file mode 100644 index 0000000000000..6d37e8e5eee5e --- /dev/null +++ b/src/test/rustdoc/anchors.no_const_anchor2.html @@ -0,0 +1 @@ +<section id="associatedconstant.X" class="associatedconstant has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#42">source</a></span><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section> diff --git a/src/test/rustdoc/anchors.no_method_anchor.html b/src/test/rustdoc/anchors.no_method_anchor.html new file mode 100644 index 0000000000000..f46d3090ed370 --- /dev/null +++ b/src/test/rustdoc/anchors.no_method_anchor.html @@ -0,0 +1 @@ +<section id="method.new" class="method has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#48">source</a></span><h4 class="code-header">pub fn <a href="#method.new" class="fnname">new</a>() -> Self</h4></section> \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_trait_method_anchor.html b/src/test/rustdoc/anchors.no_trait_method_anchor.html new file mode 100644 index 0000000000000..445a7bb560aca --- /dev/null +++ b/src/test/rustdoc/anchors.no_trait_method_anchor.html @@ -0,0 +1 @@ +<div id="method.bar" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#23">source</a></div><h4 class="code-header">fn <a href="#method.bar" class="fnname">bar</a>()</h4></div> \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_tymethod_anchor.html b/src/test/rustdoc/anchors.no_tymethod_anchor.html new file mode 100644 index 0000000000000..bb0771b10035d --- /dev/null +++ b/src/test/rustdoc/anchors.no_tymethod_anchor.html @@ -0,0 +1 @@ +<div id="tymethod.foo" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#20">source</a></div><h4 class="code-header">fn <a href="#tymethod.foo" class="fnname">foo</a>()</h4></div> \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_type_anchor.html b/src/test/rustdoc/anchors.no_type_anchor.html new file mode 100644 index 0000000000000..d317eb5005017 --- /dev/null +++ b/src/test/rustdoc/anchors.no_type_anchor.html @@ -0,0 +1 @@ +<div id="associatedtype.T" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#13">source</a></div><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></div> \ No newline at end of file diff --git a/src/test/rustdoc/anchors.no_type_anchor2.html b/src/test/rustdoc/anchors.no_type_anchor2.html new file mode 100644 index 0000000000000..72a1186bf7e30 --- /dev/null +++ b/src/test/rustdoc/anchors.no_type_anchor2.html @@ -0,0 +1 @@ +<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section> diff --git a/src/test/rustdoc/anchors.rs b/src/test/rustdoc/anchors.rs new file mode 100644 index 0000000000000..034cf8eaf4ff7 --- /dev/null +++ b/src/test/rustdoc/anchors.rs @@ -0,0 +1,49 @@ +// This test ensures that anchors are generated in the right places. + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +pub struct Foo; + +// @has 'foo/trait.Bar.html' +pub trait Bar { + // There should be no anchors here. + // @snapshot no_type_anchor - '//*[@id="associatedtype.T"]' + type T; + // There should be no anchors here. + // @snapshot no_const_anchor - '//*[@id="associatedconstant.YOLO"]' + const YOLO: u32; + + // There should be no anchors here. + // @snapshot no_tymethod_anchor - '//*[@id="tymethod.foo"]' + fn foo(); + // There should be no anchors here. + // @snapshot no_trait_method_anchor - '//*[@id="method.bar"]' + fn bar() {} +} + +// @has 'foo/struct.Foo.html' +impl Bar for Foo { + // @has - '//*[@id="associatedtype.T"]/a[@class="anchor"]' '' + type T = u32; + // @has - '//*[@id="associatedconstant.YOLO"]/a[@class="anchor"]' '' + const YOLO: u32 = 0; + + // @has - '//*[@id="method.foo"]/a[@class="anchor"]' '' + fn foo() {} + // Same check for provided "bar" method. + // @has - '//*[@id="method.bar"]/a[@class="anchor"]' '' +} + +impl Foo { + // @snapshot no_const_anchor2 - '//*[@id="associatedconstant.X"]' + // There should be no anchors here. + pub const X: i32 = 0; + // @snapshot no_type_anchor2 - '//*[@id="associatedtype.Y"]' + // There should be no anchors here. + pub type Y = u32; + // @snapshot no_method_anchor - '//*[@id="method.new"]' + // There should be no anchors here. + pub fn new() -> Self { Self } +} diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index 0ac6dc763df88..a79e93145ba7d 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -27,6 +27,10 @@ impl Bar { // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \ // 'const BAR: usize' pub const BAR: usize = 3; + + // @has - '//*[@id="associatedconstant.BAR_ESCAPED"]' \ + // "const BAR_ESCAPED: &'static str = \"<em>markup</em>\"" + pub const BAR_ESCAPED: &'static str = "<em>markup</em>"; } pub struct Baz<'a, U: 'a, T>(T, &'a [U]); diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs index d9e4ffab1c7d5..a9e5b8d001928 100644 --- a/src/test/rustdoc/assoc-types.rs +++ b/src/test/rustdoc/assoc-types.rs @@ -2,7 +2,7 @@ // @has assoc_types/trait.Index.html pub trait Index<I: ?Sized> { - // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized' + // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized' type Output: ?Sized; // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]' \ // "fn index<'a>(&'a self, index: I) -> &'a Self::Output" diff --git a/src/test/rustdoc/auto-trait-not-send.rs b/src/test/rustdoc/auto-trait-not-send.rs index 7bd4f6dbd8ce3..661d905ab639c 100644 --- a/src/test/rustdoc/auto-trait-not-send.rs +++ b/src/test/rustdoc/auto-trait-not-send.rs @@ -1,8 +1,8 @@ #![crate_name = "foo"] // @has 'foo/struct.Foo.html' -// @has - '//*[@id="impl-Send"]' 'impl !Send for Foo' -// @has - '//*[@id="impl-Sync"]' 'impl !Sync for Foo' +// @has - '//*[@id="impl-Send-for-Foo"]' 'impl !Send for Foo' +// @has - '//*[@id="impl-Sync-for-Foo"]' 'impl !Sync for Foo' pub struct Foo(*const i8); pub trait Whatever: Send {} impl<T: Send + ?Sized> Whatever for T {} diff --git a/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs new file mode 100644 index 0000000000000..4e55e7ed57630 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs @@ -0,0 +1,17 @@ +/// When reexporting this function, make sure the anonymous lifetimes are not rendered. +/// +/// https://github.com/rust-lang/rust/issues/98697 +pub fn repro<F>() +where + F: Fn(&str), +{ + unimplemented!() +} + +pub struct Extra; + +pub trait MyTrait<T> { + fn run() {} +} + +impl MyTrait<&Extra> for Extra {} diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs index 4c686730b1152..676d656dabf47 100644 --- a/src/test/rustdoc/blanket-reexport-item.rs +++ b/src/test/rustdoc/blanket-reexport-item.rs @@ -1,6 +1,6 @@ #![crate_name = "foo"] -// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T' +// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T' pub struct S2 {} mod m { pub struct S {} diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs index 12c5df2871cf5..ec44e1bc65c90 100644 --- a/src/test/rustdoc/check-source-code-urls-to-def.rs +++ b/src/test/rustdoc/check-source-code-urls-to-def.rs @@ -14,10 +14,10 @@ extern crate source_code; #[path = "auxiliary/source-code-bar.rs"] pub mod bar; -// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5-7"]' 4 +// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5"]' 4 use bar::Bar; -// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13-17"]' 'self' -// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait' +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13"]' 'self' +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait' use bar::sub::{self, Trait}; pub struct Foo; @@ -42,8 +42,8 @@ pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::Sour y.hello(); } -// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait' -// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait' +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'bar::sub::Trait' +// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14"]' 'Trait' pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {} pub trait AnotherTrait {} diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs index fc3a2731089eb..61af7de4794a6 100644 --- a/src/test/rustdoc/const-generics/const-generics-docs.rs +++ b/src/test/rustdoc/const-generics/const-generics-docs.rs @@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>; // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)' pub struct Bar<T, const N: usize>([T; N]); -// @has foo/struct.Foo.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>' +// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>' impl<const M: usize> Foo<M> where u8: Trait<M> { // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize' pub const FOO_ASSOC: usize = M + 13; @@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> { } } -// @has foo/struct.Bar.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>' +// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>' impl<const M: usize> Bar<u8, M> { // @has - '//*[@id="method.hey"]' \ // 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>' diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs index a3ef084165a8a..f1181d54ac87f 100644 --- a/src/test/rustdoc/const-generics/const-impl.rs +++ b/src/test/rustdoc/const-generics/const-impl.rs @@ -9,20 +9,20 @@ pub enum Order { } // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>' -// @has foo/struct.VSet.html '//*[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>' -// @has foo/struct.VSet.html '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>' +// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>' +// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>' pub struct VSet<T, const ORDER: Order> { inner: Vec<T>, } -// @has foo/struct.VSet.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>' +// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>' impl<T> VSet<T, { Order::Sorted }> { pub fn new() -> Self { Self { inner: Vec::new() } } } -// @has foo/struct.VSet.html '//*[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>' +// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>' impl<T> VSet<T, { Order::Unsorted }> { pub fn new() -> Self { Self { inner: Vec::new() } @@ -31,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> { pub struct Escape<const S: &'static str>; -// @has foo/struct.Escape.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>' +// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>' impl Escape<r#"<script>alert("Escape");</script>"#> { pub fn f() {} } diff --git a/src/test/rustdoc/const-value-display.rs b/src/test/rustdoc/const-value-display.rs index 0ae52592b64ba..5b2f3c48d57fa 100644 --- a/src/test/rustdoc/const-value-display.rs +++ b/src/test/rustdoc/const-value-display.rs @@ -1,9 +1,9 @@ #![crate_name = "foo"] // @has 'foo/constant.HOUR_IN_SECONDS.html' -// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = 60 * 60; // 3_600u64' +// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64' pub const HOUR_IN_SECONDS: u64 = 60 * 60; // @has 'foo/constant.NEGATIVE.html' -// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = -60 * 60; // -3_600i64' +// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64' pub const NEGATIVE: i64 = -60 * 60; diff --git a/src/test/rustdoc/decl-trailing-whitespace.declaration.html b/src/test/rustdoc/decl-trailing-whitespace.declaration.html new file mode 100644 index 0000000000000..e60caaeff383c --- /dev/null +++ b/src/test/rustdoc/decl-trailing-whitespace.declaration.html @@ -0,0 +1,7 @@ +<code>pub trait Write { + fn <a href="#tymethod.poll_write" class="fnname">poll_write</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; +<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fnname">poll_flush</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; +<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fnname">poll_close</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; + + fn <a href="#method.poll_write_vectored" class="fnname">poll_write_vectored</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... } +}</code> diff --git a/src/test/rustdoc/decl-trailing-whitespace.rs b/src/test/rustdoc/decl-trailing-whitespace.rs new file mode 100644 index 0000000000000..46a2307abef02 --- /dev/null +++ b/src/test/rustdoc/decl-trailing-whitespace.rs @@ -0,0 +1,30 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/98803>. + +#![crate_name = "foo"] + +pub struct Error; + +// @has 'foo/trait.Write.html' + +pub trait Write { + // @snapshot 'declaration' - '//*[@class="docblock item-decl"]//code' + fn poll_write( + self: Option<String>, + cx: &mut Option<String>, + buf: &mut [usize] + ) -> Option<Result<usize, Error>>; + fn poll_flush( + self: Option<String>, + cx: &mut Option<String> + ) -> Option<Result<(), Error>>; + fn poll_close( + self: Option<String>, + cx: &mut Option<String>, + ) -> Option<Result<(), Error>>; + + fn poll_write_vectored( + self: Option<String>, + cx: &mut Option<String>, + bufs: &[usize] + ) -> Option<Result<usize, Error>> {} +} diff --git a/src/test/rustdoc/double-quote-escape.rs b/src/test/rustdoc/double-quote-escape.rs index b7bbf140cfd00..350c897417d1f 100644 --- a/src/test/rustdoc/double-quote-escape.rs +++ b/src/test/rustdoc/double-quote-escape.rs @@ -1,6 +1,5 @@ #![crate_name = "foo"] - pub trait Foo<T> { fn foo() {} } @@ -8,5 +7,5 @@ pub trait Foo<T> { pub struct Bar; // @has foo/struct.Bar.html -// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E-for-Bar"]' 'Foo<unsafe extern "C" fn()>' impl Foo<unsafe extern "C" fn()> for Bar {} diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs index d18f404212fa1..83902d6f7ab13 100644 --- a/src/test/rustdoc/empty-impls.rs +++ b/src/test/rustdoc/empty-impls.rs @@ -1,19 +1,19 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html -// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send"]' 'impl Send for Foo' +// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send-for-Foo"]' 'impl Send for Foo' pub struct Foo; pub trait EmptyTrait {} -// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo' +// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait-for-Foo"]' 'impl EmptyTrait for Foo' impl EmptyTrait for Foo {} pub trait NotEmpty { fn foo(&self); } -// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo' +// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty-for-Foo"]' 'impl NotEmpty for Foo' impl NotEmpty for Foo { fn foo(&self) {} } diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs index 1268c9587f847..c6beed70abeb1 100644 --- a/src/test/rustdoc/generic-impl.rs +++ b/src/test/rustdoc/generic-impl.rs @@ -2,12 +2,12 @@ use std::fmt; -// @!has foo/struct.Bar.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' +// @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' '' pub struct Bar; -// @has foo/struct.Foo.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' +// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' pub struct Foo; -// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString"]' 'ToString' +// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString' impl fmt::Display for Foo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/test/rustdoc/generic_const_exprs.rs b/src/test/rustdoc/generic_const_exprs.rs new file mode 100644 index 0000000000000..6ff5916397546 --- /dev/null +++ b/src/test/rustdoc/generic_const_exprs.rs @@ -0,0 +1,24 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/92859>. + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +#![crate_name = "foo"] + +// @has 'foo/trait.Foo.html' + +pub trait Foo: Sized { + const WIDTH: usize; + + fn arrayify(self) -> [Self; Self::WIDTH]; +} + +impl<T: Sized> Foo for T { + const WIDTH: usize = 1; + + // @has - '//*[@id="tymethod.arrayify"]/*[@class="code-header"]' \ + // 'fn arrayify(self) -> [Self; Self::WIDTH]' + fn arrayify(self) -> [Self; Self::WIDTH] { + [self] + } +} diff --git a/src/test/rustdoc/hidden-trait-struct-impls.rs b/src/test/rustdoc/hidden-trait-struct-impls.rs index 1be956ef39308..cc3f6337719c3 100644 --- a/src/test/rustdoc/hidden-trait-struct-impls.rs +++ b/src/test/rustdoc/hidden-trait-struct-impls.rs @@ -11,11 +11,11 @@ pub struct Bar; struct Hidden; -// @!has foo/struct.Bar.html '//*[@id="impl-Foo"]' 'impl Foo for Bar' +// @!has foo/struct.Bar.html '//*[@id="impl-Foo-for-Bar"]' 'impl Foo for Bar' impl Foo for Bar {} -// @!has foo/struct.Bar.html '//*[@id="impl-Dark"]' 'impl Dark for Bar' +// @!has foo/struct.Bar.html '//*[@id="impl-Dark-for-Bar"]' 'impl Dark for Bar' impl Dark for Bar {} -// @has foo/struct.Bar.html '//*[@id="impl-Bam"]' 'impl Bam for Bar' +// @has foo/struct.Bar.html '//*[@id="impl-Bam-for-Bar"]' 'impl Bam for Bar' // @has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Bar' impl Bam for Bar {} // @!has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Hidden' diff --git a/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs new file mode 100644 index 0000000000000..644a6e1cf33c5 --- /dev/null +++ b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs @@ -0,0 +1,82 @@ +// Test that certain unevaluated constant expression arguments that are +// deemed too verbose or complex and that may leak private or +// `doc(hidden)` struct fields are not displayed in the documentation. +// +// Read the documentation of `rustdoc::clean::utils::print_const_expr` +// for further details. +#![feature(const_trait_impl, generic_const_exprs)] +#![allow(incomplete_features)] + +// @has hide_complex_unevaluated_const_arguments/trait.Stage.html +pub trait Stage { + // A helper constant that prevents const expressions containing it + // from getting fully evaluated since it doesn't have a body and + // thus is non-reducible. This allows us to specifically test the + // pretty-printing of *unevaluated* consts. + const ABSTRACT: usize; + + // Currently considered "overly complex" by the `generic_const_exprs` + // feature. If / once this expression kind gets supported, this + // unevaluated const expression could leak the private struct field. + // + // FIXME: Once the line below compiles, make this a test that + // ensures that the private field is not printed. + // + //const ARRAY0: [u8; Struct { private: () } + Self::ABSTRACT]; + + // This assoc. const could leak the private assoc. function `Struct::new`. + // Ensure that this does not happen. + // + // @has - '//*[@id="associatedconstant.ARRAY1"]' \ + // 'const ARRAY1: [u8; { _ }]' + const ARRAY1: [u8; Struct::new(/* ... */) + Self::ABSTRACT * 1_000]; + + // @has - '//*[@id="associatedconstant.VERBOSE"]' \ + // 'const VERBOSE: [u16; { _ }]' + const VERBOSE: [u16; compute("thing", 9 + 9) * Self::ABSTRACT]; + + // Check that we do not leak the private struct field contained within + // the path. The output could definitely be improved upon + // (e.g. printing sth. akin to `<Self as Helper<{ _ }>>::OUT`) but + // right now “safe is safe”. + // + // @has - '//*[@id="associatedconstant.PATH"]' \ + // 'const PATH: usize = _' + const PATH: usize = <Self as Helper<{ Struct { private: () } }>>::OUT; +} + +const fn compute(input: &str, extra: usize) -> usize { + input.len() + extra +} + +pub trait Helper<const S: Struct> { + const OUT: usize; +} + +impl<const S: Struct, St: Stage + ?Sized> Helper<S> for St { + const OUT: usize = St::ABSTRACT; +} + +// Currently in rustdoc, const arguments are not evaluated in this position +// and therefore they fall under the realm of `print_const_expr`. +// If rustdoc gets patched to evaluate const arguments, it is fine to replace +// this test as long as one can ensure that private fields are not leaked! +// +// @has hide_complex_unevaluated_const_arguments/trait.Sub.html \ +// '//*[@class="rust trait"]' \ +// 'pub trait Sub: Sup<{ _ }, { _ }> { }' +pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {} + +pub trait Sup<const N: usize, const S: Struct> {} + +pub struct Struct { private: () } + +impl Struct { + const fn new() -> Self { Self { private: () } } +} + +impl const std::ops::Add<usize> for Struct { + type Output = usize; + + fn add(self, _: usize) -> usize { 0 } +} diff --git a/src/test/rustdoc/hide-complex-unevaluated-consts.rs b/src/test/rustdoc/hide-complex-unevaluated-consts.rs new file mode 100644 index 0000000000000..ba623246a01e0 --- /dev/null +++ b/src/test/rustdoc/hide-complex-unevaluated-consts.rs @@ -0,0 +1,71 @@ +// Regression test for issue #97933. +// +// Test that certain unevaluated constant expressions that are +// deemed too verbose or complex and that may leak private or +// `doc(hidden)` struct fields are not displayed in the documentation. +// +// Read the documentation of `rustdoc::clean::utils::print_const_expr` +// for further details. + +// @has hide_complex_unevaluated_consts/trait.Container.html +pub trait Container { + // A helper constant that prevents const expressions containing it + // from getting fully evaluated since it doesn't have a body and + // thus is non-reducible. This allows us to specifically test the + // pretty-printing of *unevaluated* consts. + const ABSTRACT: i32; + + // Ensure that the private field does not get leaked: + // + // @has - '//*[@id="associatedconstant.STRUCT0"]' \ + // 'const STRUCT0: Struct = _' + const STRUCT0: Struct = Struct { private: () }; + + // @has - '//*[@id="associatedconstant.STRUCT1"]' \ + // 'const STRUCT1: (Struct,) = _' + const STRUCT1: (Struct,) = (Struct{private: /**/()},); + + // Although the struct field is public here, check that it is not + // displayed. In a future version of rustdoc, we definitely want to + // show it. However for the time being, the printing logic is a bit + // conservative. + // + // @has - '//*[@id="associatedconstant.STRUCT2"]' \ + // 'const STRUCT2: Record = _' + const STRUCT2: Record = Record { public: 5 }; + + // Test that we do not show the incredibly verbose match expr: + // + // @has - '//*[@id="associatedconstant.MATCH0"]' \ + // 'const MATCH0: i32 = _' + const MATCH0: i32 = match 234 { + 0 => 1, + _ => Self::ABSTRACT, + }; + + // @has - '//*[@id="associatedconstant.MATCH1"]' \ + // 'const MATCH1: bool = _' + const MATCH1: bool = match Self::ABSTRACT { + _ => true, + }; + + // Check that we hide complex (arithmetic) operations. + // In this case, it is a bit unfortunate since the expression + // is not *that* verbose and it might be quite useful to the reader. + // + // However in general, the expression might be quite large and + // contain match expressions and structs with private fields. + // We would need to recurse over the whole expression and even more + // importantly respect operator precedence when pretty-printing + // the potentially partially censored expression. + // For now, the implementation is quite simple and the choices + // rather conservative. + // + // @has - '//*[@id="associatedconstant.ARITH_OPS"]' \ + // 'const ARITH_OPS: i32 = _' + const ARITH_OPS: i32 = Self::ABSTRACT * 2 + 1; +} + +pub struct Struct { private: () } + +pub struct Record { pub public: i32 } diff --git a/src/test/rustdoc/impl-box.rs b/src/test/rustdoc/impl-box.rs index a371db135cff3..592b6c98587ad 100644 --- a/src/test/rustdoc/impl-box.rs +++ b/src/test/rustdoc/impl-box.rs @@ -5,7 +5,7 @@ pub struct MyType; // @has 'impl_box/struct.MyType.html' -// @has '-' '//*[@id="impl-Iterator"]' 'impl Iterator for Box<MyType>' +// @has '-' '//*[@id="impl-Iterator-for-Box%3CMyType%3E"]' 'impl Iterator for Box<MyType>' impl Iterator for Box<MyType> { type Item = (); diff --git a/src/test/rustdoc/inline_cross/macros.rs b/src/test/rustdoc/inline_cross/macros.rs index 13b4c3c7f61a4..5daa0d4baad63 100644 --- a/src/test/rustdoc/inline_cross/macros.rs +++ b/src/test/rustdoc/inline_cross/macros.rs @@ -15,5 +15,5 @@ extern crate macros; // @has - '//*[@class="docblock"]' 'docs for my_macro' // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text' // @has - '//*[@class="stab unstable"]' 'macro_test' -// @has - '//a/@href' '../src/macros/macros.rs.html#8-10' +// @has - '//a/@href' '../src/macros/macros.rs.html#8' pub use macros::my_macro; diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs index 0c70cdee91462..8a998496cf56b 100644 --- a/src/test/rustdoc/intra-doc/pub-use.rs +++ b/src/test/rustdoc/intra-doc/pub-use.rs @@ -5,21 +5,11 @@ extern crate inner; /// [mod@std::env] [g] - -// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports. -// Until then, comment out the `htmldocck` test. -// This test still does something; namely check that no incorrect errors are emitted when -// documenting the re-export. - // @has outer/index.html -// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env" -// @ has - '//a[@href="fn.f.html"]' "g" +// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env" +// @has - '//a[@href="fn.f.html"]' "g" pub use f as g; -// FIXME: same as above -/// [std::env] -extern crate self as _; - // Make sure the documentation is actually correct by documenting an inlined re-export /// [mod@std::env] // @has outer/fn.f.html diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs index 490d7e51e321d..635c3175f8138 100644 --- a/src/test/rustdoc/issue-29503.rs +++ b/src/test/rustdoc/issue-29503.rs @@ -5,7 +5,7 @@ pub trait MyTrait { fn my_string(&self) -> String; } -// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug" +// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug" impl<T> MyTrait for T where T: fmt::Debug, diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs index a8cb16ec34cc0..ac97b94fb351b 100644 --- a/src/test/rustdoc/issue-75588.rs +++ b/src/test/rustdoc/issue-75588.rs @@ -13,5 +13,5 @@ extern crate real_gimli; // @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice' pub use realcore::Deref; -// @has foo/trait.Join.html '//*[@id="impl-Join"]//h3[@class="code-header in-band"]' 'impl Join for Foo' +// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo' pub use realcore::Join; diff --git a/src/test/rustdoc/issue-78701.rs b/src/test/rustdoc/issue-78701.rs index 796d553fac45e..e3e46468f3840 100644 --- a/src/test/rustdoc/issue-78701.rs +++ b/src/test/rustdoc/issue-78701.rs @@ -5,8 +5,8 @@ // the ID is correctly derived. // @has 'foo/struct.AnotherStruct.html' -// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait"]' 1 -// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-1"]' 1 +// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3C()%3E"]' 1 +// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3CT%3E"]' 1 pub trait Something {} diff --git a/src/test/rustdoc/issue-98697.rs b/src/test/rustdoc/issue-98697.rs new file mode 100644 index 0000000000000..83e08094c0953 --- /dev/null +++ b/src/test/rustdoc/issue-98697.rs @@ -0,0 +1,17 @@ +// aux-build:issue-98697-reexport-with-anonymous-lifetime.rs +// ignore-cross-compile + +// When reexporting a function with a HRTB with anonymous lifetimes, +// make sure the anonymous lifetimes are not rendered. +// +// https://github.com/rust-lang/rust/issues/98697 + +extern crate issue_98697_reexport_with_anonymous_lifetime; + +// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>() where F: Fn(&str)' +// @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<' +pub use issue_98697_reexport_with_anonymous_lifetime::repro; + +// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl MyTrait<&Extra> for Extra' +// @!has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl<' +pub use issue_98697_reexport_with_anonymous_lifetime::Extra; diff --git a/src/test/rustdoc/primitive/primitive-generic-impl.rs b/src/test/rustdoc/primitive/primitive-generic-impl.rs index 28adff84c7032..eebb2cf5a355d 100644 --- a/src/test/rustdoc/primitive/primitive-generic-impl.rs +++ b/src/test/rustdoc/primitive/primitive-generic-impl.rs @@ -1,7 +1,7 @@ #![feature(rustdoc_internals)] #![crate_name = "foo"] -// @has foo/primitive.i32.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' +// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' #[doc(primitive = "i32")] /// Some useless docs, wouhou! diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs index ec70a69ff1060..f3e211e301742 100644 --- a/src/test/rustdoc/rfc-2632-const-trait-impl.rs +++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs @@ -29,10 +29,11 @@ pub trait Tr<T> { } } -// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const' -// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone' -// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const' -// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone' +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]' '' +// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]' '~const' +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone' +// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const' +// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone' impl<T: ~const Clone + ~const Destruct> const Tr<T> for T where Option<T>: ~const Clone + ~const Destruct, diff --git a/src/test/rustdoc/show-const-contents.rs b/src/test/rustdoc/show-const-contents.rs index f5a356bcae6ac..48b60885974af 100644 --- a/src/test/rustdoc/show-const-contents.rs +++ b/src/test/rustdoc/show-const-contents.rs @@ -21,7 +21,7 @@ pub const CONST_NEG_I32: i32 = -42; // @!has show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '// 42i32' pub const CONST_EQ_TO_VALUE_I32: i32 = 42i32; -// @has show_const_contents/constant.CONST_CALC_I32.html '= 42 + 1; // 43i32' +// @has show_const_contents/constant.CONST_CALC_I32.html '= _; // 43i32' pub const CONST_CALC_I32: i32 = 42 + 1; // @!has show_const_contents/constant.CONST_REF_I32.html '= &42;' diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs index 252a81260369a..9d2c1967757f1 100644 --- a/src/test/rustdoc/sized_trait.rs +++ b/src/test/rustdoc/sized_trait.rs @@ -11,7 +11,7 @@ pub struct Bar { pub struct Foo<T: ?Sized>(T); // @has foo/struct.Unsized.html -// @has - '//*[@id="impl-Sized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized' +// @has - '//*[@id="impl-Sized-for-Unsized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized' pub struct Unsized { data: [u8], } diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs index 0f461a1185b6e..69be9aa8d5f10 100644 --- a/src/test/rustdoc/src-links-auto-impls.rs +++ b/src/test/rustdoc/src-links-auto-impls.rs @@ -1,12 +1,12 @@ #![crate_name = "foo"] // @has foo/struct.Unsized.html -// @has - '//*[@id="impl-Sized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized' -// @!has - '//*[@id="impl-Sized"]//a[@class="srclink"]' 'source' -// @has - '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized' -// @!has - '//*[@id="impl-Sync"]//a[@class="srclink"]' 'source' -// @has - '//*[@id="impl-Any"]/h3[@class="code-header in-band"]' 'impl<T> Any for T' -// @has - '//*[@id="impl-Any"]//a[@class="srclink"]' 'source' +// @has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized' +// @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="srclink"]' 'source' +// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized' +// @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="srclink"]' 'source' +// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header in-band"]' 'impl<T> Any for T' +// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink"]' 'source' pub struct Unsized { data: [u8], } diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs index 05ccc074bf110..4f7e2dfe3b9a5 100644 --- a/src/test/rustdoc/trait-impl.rs +++ b/src/test/rustdoc/trait-impl.rs @@ -43,5 +43,5 @@ impl Trait for Struct { // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em' fn d() {} - // @has - '//*[@id="impl-Trait"]/h3//a/@href' 'trait.Trait.html' + // @has - '//*[@id="impl-Trait-for-Struct"]/h3//a/@href' 'trait.Trait.html' } diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum.html b/src/test/rustdoc/whitespace-after-where-clause.enum.html new file mode 100644 index 0000000000000..9e5bf45ae7d2f --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.enum.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a> <span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>, </span>{ + Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B), + Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum2.html b/src/test/rustdoc/whitespace-after-where-clause.enum2.html new file mode 100644 index 0000000000000..6bc47beaed125 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.enum2.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { + Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B), + Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>), +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.rs b/src/test/rustdoc/whitespace-after-where-clause.rs new file mode 100644 index 0000000000000..c36386a2aa2b5 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.rs @@ -0,0 +1,77 @@ +// This test ensures there is no whitespace before the first brace of +// trait, enum, struct and union items when they have a where clause. + +#![crate_name = "foo"] + +// @has 'foo/trait.ToOwned.html' +// @snapshot trait - '//*[@class="docblock item-decl"]' +pub trait ToOwned<T> +where T: Clone +{ + type Owned; + fn to_owned(&self) -> Self::Owned; + fn whatever(&self) -> T; +} + +// @has 'foo/trait.ToOwned2.html' +// @snapshot trait2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub trait ToOwned2<T: Clone> { + type Owned; + fn to_owned(&self) -> Self::Owned; + fn whatever(&self) -> T; +} + +// @has 'foo/enum.Cow.html' +// @snapshot enum - '//*[@class="docblock item-decl"]' +pub enum Cow<'a, B: ?Sized + 'a> +where + B: ToOwned<Clone>, +{ + Borrowed(&'a B), + Whatever(u32), +} + +// @has 'foo/enum.Cow2.html' +// @snapshot enum2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub enum Cow2<'a, B: ?Sized + ToOwned<Clone> + 'a> { + Borrowed(&'a B), + Whatever(u32), +} + +// @has 'foo/struct.Struct.html' +// @snapshot struct - '//*[@class="docblock item-decl"]' +pub struct Struct<'a, B: ?Sized + 'a> +where + B: ToOwned<Clone>, +{ + pub a: &'a B, + pub b: u32, +} + +// @has 'foo/struct.Struct2.html' +// @snapshot struct2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub struct Struct2<'a, B: ?Sized + ToOwned<Clone> + 'a> { + pub a: &'a B, + pub b: u32, +} + +// @has 'foo/union.Union.html' +// @snapshot union - '//*[@class="docblock item-decl"]' +pub union Union<'a, B: ?Sized + 'a> +where + B: ToOwned<Clone>, +{ + a: &'a B, + b: u32, +} + +// @has 'foo/union.Union2.html' +// @snapshot union2 - '//*[@class="docblock item-decl"]' +// There should be a whitespace before `{` in this case! +pub union Union2<'a, B: ?Sized + ToOwned<Clone> + 'a> { + a: &'a B, + b: u32, +} diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct.html b/src/test/rustdoc/whitespace-after-where-clause.struct.html new file mode 100644 index 0000000000000..236cc3b30d088 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.struct.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a> <span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>, </span>{ + pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B, + pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct2.html b/src/test/rustdoc/whitespace-after-where-clause.struct2.html new file mode 100644 index 0000000000000..47f5c6ba9c846 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.struct2.html @@ -0,0 +1,4 @@ +<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { + pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a </a>B, + pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>, +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait.html b/src/test/rustdoc/whitespace-after-where-clause.trait.html new file mode 100644 index 0000000000000..98f03b837b528 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.trait.html @@ -0,0 +1,6 @@ +<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned<T> <span class="where fmt-newline">where<br />    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>, </span>{ + type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>; + + fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&self) -> Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>; +<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&self) -> T; +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait2.html b/src/test/rustdoc/whitespace-after-where-clause.trait2.html new file mode 100644 index 0000000000000..35052869e762d --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.trait2.html @@ -0,0 +1,6 @@ +<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned2<T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> { + type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>; + + fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&self) -> Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>; +<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&self) -> T; +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.union.html b/src/test/rustdoc/whitespace-after-where-clause.union.html new file mode 100644 index 0000000000000..97e1bbcf339f8 --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.union.html @@ -0,0 +1,3 @@ +<div class="docblock item-decl"><pre class="rust union"><code>pub union Union<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a> <span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>>, </span>{ + /* private fields */ +}</code></pre></div> diff --git a/src/test/rustdoc/whitespace-after-where-clause.union2.html b/src/test/rustdoc/whitespace-after-where-clause.union2.html new file mode 100644 index 0000000000000..6c752a8b4c5ea --- /dev/null +++ b/src/test/rustdoc/whitespace-after-where-clause.union2.html @@ -0,0 +1,3 @@ +<div class="docblock item-decl"><pre class="rust union"><code>pub union Union2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> { + /* private fields */ +}</code></pre></div> diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs index 817d8531da905..d6f63d44ba6a8 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs @@ -16,14 +16,14 @@ use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::Span; #[derive(SessionDiagnostic)] -#[error(slug = "parser-expect-path")] +#[error(parser::expect_path)] struct DeriveSessionDiagnostic { #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -#[note(slug = "note")] +#[note(parser::add_paren)] struct Note { #[primary_span] span: Span, diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr index bac44f338b74c..bc9fcdd7bc7a5 100644 --- a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr @@ -1,4 +1,4 @@ -error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` +error: found non-existing keyword `tadam` used in `#[doc(keyword = \"...\")]` --> $DIR/existing_doc_keyword.rs:10:1 | LL | #[doc(keyword = "tadam")] diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index 402c41f376602..10bab2d889a60 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -93,7 +93,7 @@ impl CustomStruct { fn test_alias( value: CustomAlias, - reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference + reference: &CustomAlias, //~ ERROR passing `CustomAlias<'_>` by reference ) { } } diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr index 7f6e57b38f38d..69cf20656d7b1 100644 --- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -94,11 +94,11 @@ error: passing `CustomStruct` by reference LL | reference: &CustomStruct, | ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct` -error: passing `CustomAlias<>` by reference +error: passing `CustomAlias<'_>` by reference --> $DIR/rustc_pass_by_value.rs:96:20 | LL | reference: &CustomAlias, - | ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>` + | ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<'_>` error: passing `WithParameters<T, 1>` by reference --> $DIR/rustc_pass_by_value.rs:110:20 diff --git a/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs b/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs new file mode 100644 index 0000000000000..fdf1150f8d25a --- /dev/null +++ b/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs @@ -0,0 +1,81 @@ +// run-fail +// only-windows + +fn main() { + use std::fs; + use std::io::prelude::*; + use std::os::windows::prelude::*; + use std::ptr; + use std::sync::Arc; + use std::thread; + use std::time::Duration; + + const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; + + fn create_pipe_server(path: &str) -> fs::File { + let mut path0 = path.as_bytes().to_owned(); + path0.push(0); + extern "system" { + fn CreateNamedPipeA( + lpName: *const u8, + dwOpenMode: u32, + dwPipeMode: u32, + nMaxInstances: u32, + nOutBufferSize: u32, + nInBufferSize: u32, + nDefaultTimeOut: u32, + lpSecurityAttributes: *mut u8, + ) -> RawHandle; + } + + unsafe { + let h = CreateNamedPipeA(path0.as_ptr(), 3, 0, 1, 0, 0, 0, ptr::null_mut()); + assert_ne!(h as isize, -1); + fs::File::from_raw_handle(h) + } + } + + let path = "\\\\.\\pipe\\repro"; + let mut server = create_pipe_server(path); + + let client = Arc::new( + fs::OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).open(path).unwrap(), + ); + + let spawn_read = |is_first: bool| { + thread::spawn({ + let f = client.clone(); + move || { + let mut buf = [0xcc; 1]; + let mut f = f.as_ref(); + f.read(&mut buf).unwrap(); + if is_first { + assert_ne!(buf[0], 0xcc); + } else { + let b = buf[0]; // capture buf[0] + thread::sleep(Duration::from_millis(200)); + + // Check the buffer hasn't been written to after read. + dbg!(buf[0], b); + assert_eq!(buf[0], b); + } + } + }) + }; + + let t1 = spawn_read(true); + thread::sleep(Duration::from_millis(20)); + let t2 = spawn_read(false); + thread::sleep(Duration::from_millis(100)); + let _ = server.write(b"x"); + thread::sleep(Duration::from_millis(100)); + let _ = server.write(b"y"); + + // This is run fail because we need to test for the `abort`. + // That failing to run is the success case. + if t1.join().is_err() || t2.join().is_err() { + return; + } else { + panic!("success"); + } +} diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index a37d3a32571ed..a679b7b4e1913 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -114,6 +114,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) }); iter_exprs(depth - 1, &mut |e| { g(ExprKind::Closure( + ClosureBinder::NotPresent, CaptureBy::Value, Async::No, Movability::Movable, diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 84d5de173091b..0a210cbdc9430 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -1,6 +1,8 @@ // check-fail // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] +// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" + // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, // changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler // the test is just ignored on stable and beta: @@ -15,26 +17,26 @@ use rustc_span::symbol::Ident; use rustc_span::Span; extern crate rustc_macros; -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_macros::{SessionDiagnostic, LintDiagnostic, SessionSubdiagnostic}; extern crate rustc_middle; use rustc_middle::ty::Ty; extern crate rustc_errors; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, MultiSpan}; extern crate rustc_session; #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "hello-world")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct Hello {} #[derive(SessionDiagnostic)] -#[warning(code = "E0123", slug = "hello-world")] +#[warning(typeck::ambiguous_lifetime_bound, code = "E0123")] struct HelloWarn {} #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] //~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs enum SessionDiagnosticOnEnum { Foo, @@ -42,13 +44,13 @@ enum SessionDiagnosticOnEnum { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] #[error = "E0123"] //~^ ERROR `#[error = ...]` is not a valid attribute struct WrongStructAttrStyle {} #[derive(SessionDiagnostic)] -#[nonsense(code = "E0123", slug = "foo")] +#[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] //~^ ERROR `#[nonsense(...)]` is not a valid attribute //~^^ ERROR diagnostic kind not specified //~^^^ ERROR cannot find attribute `nonsense` in this scope @@ -57,31 +59,39 @@ struct InvalidStructAttr {} #[derive(SessionDiagnostic)] #[error("E0123")] //~^ ERROR `#[error("...")]` is not a valid attribute -//~^^ ERROR `slug` not specified +//~^^ ERROR diagnostic slug not specified struct InvalidLitNestedAttr {} #[derive(SessionDiagnostic)] -#[error(nonsense, code = "E0123", slug = "foo")] -//~^ ERROR `#[error(nonsense)]` is not a valid attribute +#[error(nonsense, code = "E0123")] +//~^ ERROR cannot find value `nonsense` in module `rustc_errors::fluent` struct InvalidNestedStructAttr {} #[derive(SessionDiagnostic)] #[error(nonsense("foo"), code = "E0123", slug = "foo")] //~^ ERROR `#[error(nonsense(...))]` is not a valid attribute +//~^^ ERROR diagnostic slug not specified struct InvalidNestedStructAttr1 {} #[derive(SessionDiagnostic)] #[error(nonsense = "...", code = "E0123", slug = "foo")] //~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute +//~^^ ERROR diagnostic slug not specified struct InvalidNestedStructAttr2 {} #[derive(SessionDiagnostic)] #[error(nonsense = 4, code = "E0123", slug = "foo")] //~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute +//~^^ ERROR diagnostic slug not specified struct InvalidNestedStructAttr3 {} #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")] +//~^ ERROR `#[error(slug = ...)]` is not a valid attribute +struct InvalidNestedStructAttr4 {} + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct WrongPlaceField { #[suggestion = "bar"] //~^ ERROR `#[suggestion = ...]` is not a valid attribute @@ -89,52 +99,53 @@ struct WrongPlaceField { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] -#[error(code = "E0456", slug = "bar")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0456")] //~^ ERROR specified multiple times //~^^ ERROR specified multiple times //~^^^ ERROR specified multiple times struct ErrorSpecifiedTwice {} #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] -#[warning(code = "E0293", slug = "bar")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] //~^ ERROR specified multiple times //~^^ ERROR specified multiple times //~^^^ ERROR specified multiple times struct WarnSpecifiedAfterError {} #[derive(SessionDiagnostic)] -#[error(code = "E0456", code = "E0457", slug = "bar")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] //~^ ERROR specified multiple times struct CodeSpecifiedTwice {} #[derive(SessionDiagnostic)] -#[error(code = "E0456", slug = "foo", slug = "bar")] -//~^ ERROR specified multiple times +#[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")] +//~^ ERROR `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute struct SlugSpecifiedTwice {} #[derive(SessionDiagnostic)] struct KindNotProvided {} //~ ERROR diagnostic kind not specified #[derive(SessionDiagnostic)] -#[error(code = "E0456")] //~ ERROR `slug` not specified +#[error(code = "E0456")] +//~^ ERROR diagnostic slug not specified struct SlugNotProvided {} #[derive(SessionDiagnostic)] -#[error(slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound)] struct CodeNotProvided {} #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct MessageWrongType { #[primary_span] - //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` + //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` foo: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct InvalidPathFieldAttr { #[nonsense] //~^ ERROR `#[nonsense]` is not a valid attribute @@ -143,34 +154,34 @@ struct InvalidPathFieldAttr { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithField { name: String, - #[label = "bar"] + #[label(typeck::label)] span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithMessageAppliedToField { - #[label = "bar"] - //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span` + #[label(typeck::label)] + //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` name: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithNonexistentField { - #[suggestion(message = "bar", code = "{name}")] + #[suggestion(typeck::suggestion, code = "{name}")] //~^ ERROR `name` doesn't refer to a field on this type suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] //~^ ERROR invalid format string: expected `'}'` -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorMissingClosingBrace { - #[suggestion(message = "bar", code = "{name")] + #[suggestion(typeck::suggestion, code = "{name")] suggestion: (Span, Applicability), name: String, val: usize, @@ -178,48 +189,48 @@ struct ErrorMissingClosingBrace { #[derive(SessionDiagnostic)] //~^ ERROR invalid format string: unmatched `}` -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorMissingOpeningBrace { - #[suggestion(message = "bar", code = "name}")] + #[suggestion(typeck::suggestion, code = "name}")] suggestion: (Span, Applicability), name: String, val: usize, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct LabelOnSpan { - #[label = "bar"] + #[label(typeck::label)] sp: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct LabelOnNonSpan { - #[label = "bar"] - //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span` + #[label(typeck::label)] + //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` id: u32, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct Suggest { - #[suggestion(message = "bar", code = "This is the suggested code")] - #[suggestion_short(message = "qux", code = "This is the suggested code")] - #[suggestion_hidden(message = "foobar", code = "This is the suggested code")] - #[suggestion_verbose(message = "fooqux", code = "This is the suggested code")] + #[suggestion(typeck::suggestion, code = "This is the suggested code")] + #[suggestion_short(typeck::suggestion, code = "This is the suggested code")] + #[suggestion_hidden(typeck::suggestion, code = "This is the suggested code")] + #[suggestion_verbose(typeck::suggestion, code = "This is the suggested code")] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithoutCode { - #[suggestion(message = "bar")] + #[suggestion(typeck::suggestion)] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithBadKey { #[suggestion(nonsense = "bar")] //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute @@ -227,7 +238,7 @@ struct SuggestWithBadKey { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithShorthandMsg { #[suggestion(msg = "bar")] //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute @@ -235,91 +246,91 @@ struct SuggestWithShorthandMsg { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithoutMsg { #[suggestion(code = "bar")] suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithTypesSwapped { - #[suggestion(message = "bar", code = "This is suggested code")] + #[suggestion(typeck::suggestion, code = "This is suggested code")] suggestion: (Applicability, Span), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithWrongTypeApplicabilityOnly { - #[suggestion(message = "bar", code = "This is suggested code")] + #[suggestion(typeck::suggestion, code = "This is suggested code")] //~^ ERROR wrong field type for suggestion suggestion: Applicability, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithSpanOnly { - #[suggestion(message = "bar", code = "This is suggested code")] + #[suggestion(typeck::suggestion, code = "This is suggested code")] suggestion: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithDuplicateSpanAndApplicability { - #[suggestion(message = "bar", code = "This is suggested code")] + #[suggestion(typeck::suggestion, code = "This is suggested code")] //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span` suggestion: (Span, Span, Applicability), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct SuggestWithDuplicateApplicabilityAndSpan { - #[suggestion(message = "bar", code = "This is suggested code")] + #[suggestion(typeck::suggestion, code = "This is suggested code")] //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one suggestion: (Applicability, Applicability, Span), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct WrongKindOfAnnotation { - #[label("bar")] - //~^ ERROR `#[label(...)]` is not a valid attribute + #[label = "bar"] + //~^ ERROR `#[label = ...]` is not a valid attribute z: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct OptionsInErrors { - #[label = "bar"] + #[label(typeck::label)] label: Option<Span>, - #[suggestion(message = "bar")] + #[suggestion(typeck::suggestion)] opt_sugg: Option<(Span, Applicability)>, } #[derive(SessionDiagnostic)] -#[error(code = "E0456", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0456")] struct MoveOutOfBorrowError<'tcx> { name: Ident, ty: Ty<'tcx>, #[primary_span] - #[label = "bar"] + #[label(typeck::label)] span: Span, - #[label = "qux"] + #[label(typeck::label)] other_span: Span, - #[suggestion(message = "bar", code = "{name}.clone()")] + #[suggestion(typeck::suggestion, code = "{name}.clone()")] opt_sugg: Option<(Span, Applicability)>, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithLifetime<'a> { - #[label = "bar"] + #[label(typeck::label)] span: Span, name: &'a str, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithDefaultLabelAttr<'a> { #[label] span: Span, @@ -328,7 +339,7 @@ struct ErrorWithDefaultLabelAttr<'a> { #[derive(SessionDiagnostic)] //~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ArgFieldWithoutSkip { #[primary_span] span: Span, @@ -336,7 +347,7 @@ struct ArgFieldWithoutSkip { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ArgFieldWithSkip { #[primary_span] span: Span, @@ -347,132 +358,132 @@ struct ArgFieldWithSkip { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithSpannedNote { #[note] span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithSpannedNoteCustom { - #[note = "bar"] + #[note(typeck::note)] span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] #[note] struct ErrorWithNote { val: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] -#[note = "bar"] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[note(typeck::note)] struct ErrorWithNoteCustom { val: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithSpannedHelp { #[help] span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithSpannedHelpCustom { - #[help = "bar"] + #[help(typeck::help)] span: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] #[help] struct ErrorWithHelp { val: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] -#[help = "bar"] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[help(typeck::help)] struct ErrorWithHelpCustom { val: String, } #[derive(SessionDiagnostic)] #[help] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithHelpWrongOrder { val: String, } #[derive(SessionDiagnostic)] -#[help = "bar"] -#[error(code = "E0123", slug = "foo")] +#[help(typeck::help)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithHelpCustomWrongOrder { val: String, } #[derive(SessionDiagnostic)] #[note] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithNoteWrongOrder { val: String, } #[derive(SessionDiagnostic)] -#[note = "bar"] -#[error(code = "E0123", slug = "foo")] +#[note(typeck::note)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ErrorWithNoteCustomWrongOrder { val: String, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ApplicabilityInBoth { - #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")] + #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")] //~^ ERROR applicability cannot be set in both the field and attribute suggestion: (Span, Applicability), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct InvalidApplicability { - #[suggestion(message = "bar", code = "...", applicability = "batman")] + #[suggestion(typeck::suggestion, code = "...", applicability = "batman")] //~^ ERROR invalid applicability suggestion: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct ValidApplicability { - #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")] + #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")] suggestion: Span, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct NoApplicability { - #[suggestion(message = "bar", code = "...")] + #[suggestion(typeck::suggestion, code = "...")] suggestion: Span, } #[derive(SessionSubdiagnostic)] -#[note(slug = "note")] +#[note(parser::add_paren)] struct Note; #[derive(SessionDiagnostic)] -#[error(slug = "subdiagnostic")] +#[error(typeck::ambiguous_lifetime_bound)] struct Subdiagnostic { #[subdiagnostic] note: Note, } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct VecField { #[primary_span] #[label] @@ -480,23 +491,78 @@ struct VecField { } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct UnitField { #[primary_span] spans: Span, #[help] foo: (), - #[help = "a"] + #[help(typeck::help)] bar: (), } #[derive(SessionDiagnostic)] -#[error(code = "E0123", slug = "foo")] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] struct OptUnitField { #[primary_span] spans: Span, #[help] foo: Option<()>, - #[help = "a"] + #[help(typeck::help)] bar: Option<()>, } + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct LabelWithTrailingPath { + #[label(typeck::label, foo)] + //~^ ERROR `#[label(...)]` is not a valid attribute + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct LabelWithTrailingNameValue { + #[label(typeck::label, foo = "...")] + //~^ ERROR `#[label(...)]` is not a valid attribute + span: Span, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct LabelWithTrailingList { + #[label(typeck::label, foo("..."))] + //~^ ERROR `#[label(...)]` is not a valid attribute + span: Span, +} + +#[derive(SessionDiagnostic)] +#[lint(typeck::ambiguous_lifetime_bound)] +//~^ ERROR only `#[error(..)]` and `#[warning(..)]` are supported +struct LintsBad { +} + +#[derive(LintDiagnostic)] +#[lint(typeck::ambiguous_lifetime_bound)] +struct LintsGood { +} + +#[derive(LintDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound)] +//~^ ERROR only `#[lint(..)]` is supported +struct ErrorsBad { +} + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +struct ErrorWithMultiSpan { + #[primary_span] + span: MultiSpan, +} + +#[derive(SessionDiagnostic)] +#[error(typeck::ambiguous_lifetime_bound, code = "E0123")] +#[warn_] +struct ErrorWithWarn { + val: String, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 85ea44ec278c0..c1080aa24521f 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,7 +1,7 @@ error: `#[derive(SessionDiagnostic)]` can only be used on structs - --> $DIR/diagnostic-derive.rs:37:1 + --> $DIR/diagnostic-derive.rs:39:1 | -LL | / #[error(code = "E0123", slug = "foo")] +LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | LL | | enum SessionDiagnosticOnEnum { LL | | Foo, @@ -10,23 +10,23 @@ LL | | } | |_^ error: `#[error = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:46:1 + --> $DIR/diagnostic-derive.rs:48:1 | LL | #[error = "E0123"] | ^^^^^^^^^^^^^^^^^^ error: `#[nonsense(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:51:1 + --> $DIR/diagnostic-derive.rs:53:1 | -LL | #[nonsense(code = "E0123", slug = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: only `error` and `warning` are valid attributes + = help: only `error`, `warning`, `help`, `note` and `warn_` are valid attributes error: diagnostic kind not specified - --> $DIR/diagnostic-derive.rs:51:1 + --> $DIR/diagnostic-derive.rs:53:1 | -LL | / #[nonsense(code = "E0123", slug = "foo")] +LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | LL | | LL | | @@ -36,13 +36,15 @@ LL | | struct InvalidStructAttr {} = help: use the `#[error(...)]` attribute to create an error error: `#[error("...")]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:58:9 + --> $DIR/diagnostic-derive.rs:60:9 | LL | #[error("E0123")] | ^^^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug -error: `slug` not specified - --> $DIR/diagnostic-derive.rs:58:1 +error: diagnostic slug not specified + --> $DIR/diagnostic-derive.rs:60:1 | LL | / #[error("E0123")] LL | | @@ -50,183 +52,215 @@ LL | | LL | | struct InvalidLitNestedAttr {} | |______________________________^ | - = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug - -error: `#[error(nonsense)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:64:9 - | -LL | #[error(nonsense, code = "E0123", slug = "foo")] - | ^^^^^^^^ + = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(nonsense(...))]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:69:9 + --> $DIR/diagnostic-derive.rs:71:9 | LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")] | ^^^^^^^^^^^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug + +error: diagnostic slug not specified + --> $DIR/diagnostic-derive.rs:71:1 + | +LL | / #[error(nonsense("foo"), code = "E0123", slug = "foo")] +LL | | +LL | | +LL | | struct InvalidNestedStructAttr1 {} + | |__________________________________^ + | + = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:74:9 + --> $DIR/diagnostic-derive.rs:77:9 | LL | #[error(nonsense = "...", code = "E0123", slug = "foo")] | ^^^^^^^^^^^^^^^^ | - = help: only `slug` and `code` are valid nested attributes + = help: first argument of the attribute should be the diagnostic slug + +error: diagnostic slug not specified + --> $DIR/diagnostic-derive.rs:77:1 + | +LL | / #[error(nonsense = "...", code = "E0123", slug = "foo")] +LL | | +LL | | +LL | | struct InvalidNestedStructAttr2 {} + | |__________________________________^ + | + = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:79:9 + --> $DIR/diagnostic-derive.rs:83:9 | LL | #[error(nonsense = 4, code = "E0123", slug = "foo")] | ^^^^^^^^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug -error: `#[suggestion = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:86:5 +error: diagnostic slug not specified + --> $DIR/diagnostic-derive.rs:83:1 | -LL | #[suggestion = "bar"] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")] +LL | | +LL | | +LL | | struct InvalidNestedStructAttr3 {} + | |__________________________________^ | - = help: only `label`, `note` and `help` are valid field attributes + = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` -error: specified multiple times - --> $DIR/diagnostic-derive.rs:93:1 +error: `#[error(slug = ...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:89:59 | -LL | #[error(code = "E0456", slug = "bar")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")] + | ^^^^^^^^^^^^ | -note: previously specified here - --> $DIR/diagnostic-derive.rs:92:1 + = help: only `code` is a valid nested attributes following the slug + +error: `#[suggestion = ...]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:96:5 | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[suggestion = "bar"] + | ^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:93:16 + --> $DIR/diagnostic-derive.rs:103:1 | -LL | #[error(code = "E0456", slug = "bar")] - | ^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:92:16 + --> $DIR/diagnostic-derive.rs:102:1 | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:93:32 + --> $DIR/diagnostic-derive.rs:103:1 | -LL | #[error(code = "E0456", slug = "bar")] - | ^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:92:32 + --> $DIR/diagnostic-derive.rs:102:1 | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:101:1 + --> $DIR/diagnostic-derive.rs:103:50 | -LL | #[warning(code = "E0293", slug = "bar")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] + | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100:1 + --> $DIR/diagnostic-derive.rs:102:50 | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:101:18 + --> $DIR/diagnostic-derive.rs:111:1 | -LL | #[warning(code = "E0293", slug = "bar")] - | ^^^^^^^ +LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100:16 + --> $DIR/diagnostic-derive.rs:110:1 | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:101:34 + --> $DIR/diagnostic-derive.rs:111:1 | -LL | #[warning(code = "E0293", slug = "bar")] - | ^^^^^ +LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100:32 + --> $DIR/diagnostic-derive.rs:110:1 | -LL | #[error(code = "E0123", slug = "foo")] - | ^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:108:32 + --> $DIR/diagnostic-derive.rs:111:52 | -LL | #[error(code = "E0456", code = "E0457", slug = "bar")] - | ^^^^^^^ +LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] + | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:108:16 + --> $DIR/diagnostic-derive.rs:110:50 | -LL | #[error(code = "E0456", code = "E0457", slug = "bar")] - | ^^^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] + | ^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:113:46 + --> $DIR/diagnostic-derive.rs:118:66 | -LL | #[error(code = "E0456", slug = "foo", slug = "bar")] - | ^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] + | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:113:32 + --> $DIR/diagnostic-derive.rs:118:50 + | +LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] + | ^^^^^^^ + +error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:123:43 | -LL | #[error(code = "E0456", slug = "foo", slug = "bar")] - | ^^^^^ +LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic kind not specified - --> $DIR/diagnostic-derive.rs:118:1 + --> $DIR/diagnostic-derive.rs:128:1 | LL | struct KindNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use the `#[error(...)]` attribute to create an error -error: `slug` not specified - --> $DIR/diagnostic-derive.rs:121:1 +error: diagnostic slug not specified + --> $DIR/diagnostic-derive.rs:131:1 | LL | / #[error(code = "E0456")] +LL | | LL | | struct SlugNotProvided {} | |_________________________^ | - = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug + = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` -error: the `#[primary_span]` attribute can only be applied to fields of type `Span` - --> $DIR/diagnostic-derive.rs:131:5 +error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/diagnostic-derive.rs:142:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: `#[nonsense]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:139:5 + --> $DIR/diagnostic-derive.rs:150:5 | LL | #[nonsense] | ^^^^^^^^^^^ | = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes -error: the `#[label = ...]` attribute can only be applied to fields of type `Span` - --> $DIR/diagnostic-derive.rs:156:5 +error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/diagnostic-derive.rs:167:5 | -LL | #[label = "bar"] - | ^^^^^^^^^^^^^^^^ +LL | #[label(typeck::label)] + | ^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/diagnostic-derive.rs:164:42 + --> $DIR/diagnostic-derive.rs:175:45 | -LL | #[suggestion(message = "bar", code = "{name}")] - | ^^^^^^^^ +LL | #[suggestion(typeck::suggestion, code = "{name}")] + | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:169:16 + --> $DIR/diagnostic-derive.rs:180:16 | LL | #[derive(SessionDiagnostic)] | - ^ expected `'}'` in format string @@ -237,7 +271,7 @@ LL | #[derive(SessionDiagnostic)] = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:179:15 + --> $DIR/diagnostic-derive.rs:190:15 | LL | #[derive(SessionDiagnostic)] | ^ unmatched `}` in format string @@ -245,14 +279,14 @@ LL | #[derive(SessionDiagnostic)] = note: if you intended to print `}`, you can escape it using `}}` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: the `#[label = ...]` attribute can only be applied to fields of type `Span` - --> $DIR/diagnostic-derive.rs:199:5 +error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/diagnostic-derive.rs:210:5 | -LL | #[label = "bar"] - | ^^^^^^^^^^^^^^^^ +LL | #[label(typeck::label)] + | ^^^^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:224:18 + --> $DIR/diagnostic-derive.rs:235:18 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^^^^^^^^^ @@ -260,7 +294,7 @@ LL | #[suggestion(nonsense = "bar")] = help: only `message`, `code` and `applicability` are valid field attributes error: `#[suggestion(msg = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:232:18 + --> $DIR/diagnostic-derive.rs:243:18 | LL | #[suggestion(msg = "bar")] | ^^^^^^^^^^^ @@ -268,9 +302,9 @@ LL | #[suggestion(msg = "bar")] = help: only `message`, `code` and `applicability` are valid field attributes error: wrong field type for suggestion - --> $DIR/diagnostic-derive.rs:254:5 + --> $DIR/diagnostic-derive.rs:265:5 | -LL | / #[suggestion(message = "bar", code = "This is suggested code")] +LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | LL | | suggestion: Applicability, | |_____________________________^ @@ -278,73 +312,112 @@ LL | | suggestion: Applicability, = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` error: type of field annotated with `#[suggestion(...)]` contains more than one `Span` - --> $DIR/diagnostic-derive.rs:269:5 + --> $DIR/diagnostic-derive.rs:280:5 | -LL | / #[suggestion(message = "bar", code = "This is suggested code")] +LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | LL | | suggestion: (Span, Span, Applicability), | |___________________________________________^ error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability - --> $DIR/diagnostic-derive.rs:277:5 + --> $DIR/diagnostic-derive.rs:288:5 | -LL | / #[suggestion(message = "bar", code = "This is suggested code")] +LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | LL | | suggestion: (Applicability, Applicability, Span), | |____________________________________________________^ -error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:285:5 - | -LL | #[label("bar")] - | ^^^^^^^^^^^^^^^ +error: `#[label = ...]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:296:5 | - = help: only `suggestion{,_short,_hidden,_verbose}` are valid field attributes +LL | #[label = "bar"] + | ^^^^^^^^^^^^^^^^ error: applicability cannot be set in both the field and attribute - --> $DIR/diagnostic-derive.rs:436:49 + --> $DIR/diagnostic-derive.rs:447:52 | -LL | #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:444:49 + --> $DIR/diagnostic-derive.rs:455:52 + | +LL | #[suggestion(typeck::suggestion, code = "...", applicability = "batman")] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[label(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:518:5 + | +LL | #[label(typeck::label, foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[label(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:526:5 + | +LL | #[label(typeck::label, foo = "...")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[label(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:534:5 + | +LL | #[label(typeck::label, foo("..."))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: only `#[error(..)]` and `#[warning(..)]` are supported + --> $DIR/diagnostic-derive.rs:540:1 + | +LL | / #[lint(typeck::ambiguous_lifetime_bound)] +LL | | +LL | | struct LintsBad { +LL | | } + | |_^ | -LL | #[suggestion(message = "bar", code = "...", applicability = "batman")] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use the `#[error(...)]` attribute to create a error + +error: only `#[lint(..)]` is supported + --> $DIR/diagnostic-derive.rs:551:1 + | +LL | / #[error(typeck::ambiguous_lifetime_bound)] +LL | | +LL | | struct ErrorsBad { +LL | | } + | |_^ + | + = help: use the `#[lint(...)]` attribute to create a lint error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:51:3 + --> $DIR/diagnostic-derive.rs:53:3 | -LL | #[nonsense(code = "E0123", slug = "foo")] +LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:139:7 + --> $DIR/diagnostic-derive.rs:150:7 | LL | #[nonsense] | ^^^^^^^^ +error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent` + --> $DIR/diagnostic-derive.rs:66:9 + | +LL | #[error(nonsense, code = "E0123")] + | ^^^^^^^^ not found in `rustc_errors::fluent` + error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive.rs:329:10 + --> $DIR/diagnostic-derive.rs:340:10 | LL | #[derive(SessionDiagnostic)] | ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello` | - = help: the following other types implement trait `IntoDiagnosticArg`: - &'a str - Ident - String - Symbol - rustc_middle::ty::Ty<'tcx> - usize + = help: normalized in stderr note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19 + --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:539:19 | LL | arg: impl IntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 39 previous errors +error: aborting due to 48 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0425. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index bb406c35c0eef..16da25c402b57 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -20,7 +20,7 @@ use rustc_span::Span; use rustc_macros::SessionSubdiagnostic; #[derive(SessionSubdiagnostic)] -#[label(slug = "label-a")] +#[label(parser::add_paren)] struct A { #[primary_span] span: Span, @@ -29,13 +29,13 @@ struct A { #[derive(SessionSubdiagnostic)] enum B { - #[label(slug = "label-b-a")] + #[label(parser::add_paren)] A { #[primary_span] span: Span, var: String, }, - #[label(slug = "label-b-b")] + #[label(parser::add_paren)] B { #[primary_span] span: Span, @@ -44,7 +44,7 @@ enum B { } #[derive(SessionSubdiagnostic)] -#[label(slug = "label-c")] +#[label(parser::add_paren)] //~^ ERROR label without `#[primary_span]` field struct C { var: String, @@ -116,7 +116,8 @@ struct K { #[derive(SessionSubdiagnostic)] #[label(slug)] -//~^ ERROR `#[label(slug)]` is not a valid attribute +//~^ ERROR cannot find value `slug` in module `rustc_errors::fluent` +//~^^ NOTE not found in `rustc_errors::fluent` struct L { #[primary_span] span: Span, @@ -125,7 +126,7 @@ struct L { #[derive(SessionSubdiagnostic)] #[label()] -//~^ ERROR `slug` must be set in a `#[label(...)]` attribute +//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute struct M { #[primary_span] span: Span, @@ -133,7 +134,7 @@ struct M { } #[derive(SessionSubdiagnostic)] -#[label(code = "...")] +#[label(parser::add_paren, code = "...")] //~^ ERROR `code` is not a valid nested attribute of a `label` attribute struct N { #[primary_span] @@ -141,12 +142,21 @@ struct N { var: String, } +#[derive(SessionSubdiagnostic)] +#[label(parser::add_paren, applicability = "machine-applicable")] +//~^ ERROR `applicability` is not a valid nested attribute of a `label` attribute +struct O { + #[primary_span] + span: Span, + var: String, +} + #[derive(SessionSubdiagnostic)] #[foo] //~^ ERROR cannot find attribute `foo` in this scope //~^^ ERROR unsupported type attribute for subdiagnostic enum -enum O { - #[label(slug = "...")] +enum P { + #[label(parser::add_paren)] A { #[primary_span] span: Span, @@ -155,7 +165,7 @@ enum O { } #[derive(SessionSubdiagnostic)] -enum P { +enum Q { #[bar] //~^ ERROR `#[bar]` is not a valid attribute //~^^ ERROR cannot find attribute `bar` in this scope @@ -167,7 +177,7 @@ enum P { } #[derive(SessionSubdiagnostic)] -enum Q { +enum R { #[bar = "..."] //~^ ERROR `#[bar = ...]` is not a valid attribute //~^^ ERROR cannot find attribute `bar` in this scope @@ -179,7 +189,7 @@ enum Q { } #[derive(SessionSubdiagnostic)] -enum R { +enum S { #[bar = 4] //~^ ERROR `#[bar = ...]` is not a valid attribute //~^^ ERROR cannot find attribute `bar` in this scope @@ -191,7 +201,7 @@ enum R { } #[derive(SessionSubdiagnostic)] -enum S { +enum T { #[bar("...")] //~^ ERROR `#[bar("...")]` is not a valid attribute //~^^ ERROR cannot find attribute `bar` in this scope @@ -203,9 +213,9 @@ enum S { } #[derive(SessionSubdiagnostic)] -enum T { +enum U { #[label(code = "...")] -//~^ ERROR `code` is not a valid nested attribute of a `label` +//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute A { #[primary_span] span: Span, @@ -214,8 +224,8 @@ enum T { } #[derive(SessionSubdiagnostic)] -enum U { - #[label(slug = "label-u")] +enum V { + #[label(parser::add_paren)] A { #[primary_span] span: Span, @@ -230,17 +240,17 @@ enum U { } #[derive(SessionSubdiagnostic)] -#[label(slug = "...")] +#[label(parser::add_paren)] //~^ ERROR label without `#[primary_span]` field -struct V { +struct W { #[primary_span] - //~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span` + //~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` span: String, } #[derive(SessionSubdiagnostic)] -#[label(slug = "...")] -struct W { +#[label(parser::add_paren)] +struct X { #[primary_span] span: Span, #[applicability] @@ -249,8 +259,8 @@ struct W { } #[derive(SessionSubdiagnostic)] -#[label(slug = "...")] -struct X { +#[label(parser::add_paren)] +struct Y { #[primary_span] span: Span, #[bar] @@ -260,8 +270,8 @@ struct X { } #[derive(SessionSubdiagnostic)] -#[label(slug = "...")] -struct Y { +#[label(parser::add_paren)] +struct Z { #[primary_span] span: Span, #[bar = "..."] @@ -271,8 +281,8 @@ struct Y { } #[derive(SessionSubdiagnostic)] -#[label(slug = "...")] -struct Z { +#[label(parser::add_paren)] +struct AA { #[primary_span] span: Span, #[bar("...")] @@ -282,8 +292,8 @@ struct Z { } #[derive(SessionSubdiagnostic)] -#[label(slug = "label-aa")] -struct AA { +#[label(parser::add_paren)] +struct AB { #[primary_span] span: Span, #[skip_arg] @@ -291,36 +301,35 @@ struct AA { } #[derive(SessionSubdiagnostic)] -union AB { +union AC { //~^ ERROR unexpected unsupported untagged union span: u32, b: u64 } #[derive(SessionSubdiagnostic)] -#[label(slug = "label-ac-1")] +#[label(parser::add_paren)] //~^ NOTE previously specified here //~^^ NOTE previously specified here -#[label(slug = "label-ac-2")] +#[label(parser::add_paren)] //~^ ERROR specified multiple times //~^^ ERROR specified multiple times -struct AC { +struct AD { #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -#[label(slug = "label-ad-1", slug = "label-ad-2")] -//~^ ERROR specified multiple times -//~^^ NOTE previously specified here -struct AD { +#[label(parser::add_paren, parser::add_paren)] +//~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute +struct AE { #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -#[label(slug = "label-ad-1")] -struct AE { +#[label(parser::add_paren)] +struct AF { #[primary_span] //~^ NOTE previously specified here span_a: Span, @@ -330,15 +339,15 @@ struct AE { } #[derive(SessionSubdiagnostic)] -struct AF { +struct AG { //~^ ERROR subdiagnostic kind not specified #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "suggestion-af", code = "...")] -struct AG { +#[suggestion(parser::add_paren, code = "...")] +struct AH { #[primary_span] span: Span, #[applicability] @@ -347,8 +356,8 @@ struct AG { } #[derive(SessionSubdiagnostic)] -enum AH { - #[suggestion(slug = "suggestion-ag-a", code = "...")] +enum AI { + #[suggestion(parser::add_paren, code = "...")] A { #[primary_span] span: Span, @@ -356,7 +365,7 @@ enum AH { applicability: Applicability, var: String, }, - #[suggestion(slug = "suggestion-ag-b", code = "...")] + #[suggestion(parser::add_paren, code = "...")] B { #[primary_span] span: Span, @@ -367,10 +376,10 @@ enum AH { } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code = "...", code = "...")] +#[suggestion(parser::add_paren, code = "...", code = "...")] //~^ ERROR specified multiple times //~^^ NOTE previously specified here -struct AI { +struct AJ { #[primary_span] span: Span, #[applicability] @@ -378,8 +387,8 @@ struct AI { } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code = "...")] -struct AJ { +#[suggestion(parser::add_paren, code = "...")] +struct AK { #[primary_span] span: Span, #[applicability] @@ -391,9 +400,9 @@ struct AJ { } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code = "...")] +#[suggestion(parser::add_paren, code = "...")] //~^ ERROR suggestion without `applicability` -struct AK { +struct AL { #[primary_span] span: Span, #[applicability] @@ -402,17 +411,17 @@ struct AK { } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code = "...")] +#[suggestion(parser::add_paren, code = "...")] //~^ ERROR suggestion without `applicability` -struct AL { +struct AM { #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...")] +#[suggestion(parser::add_paren)] //~^ ERROR suggestion without `code = "..."` -struct AM { +struct AN { #[primary_span] span: Span, #[applicability] @@ -420,34 +429,34 @@ struct AM { } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code ="...", applicability = "foo")] +#[suggestion(parser::add_paren, code ="...", applicability = "foo")] //~^ ERROR invalid applicability -struct AN { +struct AO { #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -#[help(slug = "label-am")] -struct AO { +#[help(parser::add_paren)] +struct AP { var: String } #[derive(SessionSubdiagnostic)] -#[note(slug = "label-an")] -struct AP; +#[note(parser::add_paren)] +struct AQ; #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code = "...")] +#[suggestion(parser::add_paren, code = "...")] //~^ ERROR suggestion without `applicability` //~^^ ERROR suggestion without `#[primary_span]` field -struct AQ { +struct AR { var: String, } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code ="...", applicability = "machine-applicable")] -struct AR { +#[suggestion(parser::add_paren, code ="...", applicability = "machine-applicable")] +struct AS { #[primary_span] span: Span, } @@ -455,8 +464,8 @@ struct AR { #[derive(SessionSubdiagnostic)] #[label] //~^ ERROR unsupported type attribute for subdiagnostic enum -enum AS { - #[label(slug = "...")] +enum AT { + #[label(parser::add_paren)] A { #[primary_span] span: Span, @@ -465,24 +474,24 @@ enum AS { } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")] -struct AT { +#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] +struct AU { #[primary_span] span: Span, var: String, } #[derive(SessionSubdiagnostic)] -#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")] +#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] //~^ ERROR `var` doesn't refer to a field on this type -struct AU { +struct AV { #[primary_span] span: Span, } #[derive(SessionSubdiagnostic)] -enum AV { - #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")] +enum AW { + #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] A { #[primary_span] span: Span, @@ -491,11 +500,23 @@ enum AV { } #[derive(SessionSubdiagnostic)] -enum AW { - #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")] +enum AX { + #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] //~^ ERROR `var` doesn't refer to a field on this type A { #[primary_span] span: Span, } } + +#[derive(SessionSubdiagnostic)] +#[warn_(parser::add_paren)] +struct AY { +} + +#[derive(SessionSubdiagnostic)] +#[warn_(parser::add_paren)] +struct AZ { + #[primary_span] + span: Span, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 4984cc4b3186c..a289c4fffd936 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -1,7 +1,7 @@ error: label without `#[primary_span]` field --> $DIR/subdiagnostic-derive.rs:47:1 | -LL | / #[label(slug = "label-c")] +LL | / #[label(parser::add_paren)] LL | | LL | | struct C { LL | | var: String, @@ -32,98 +32,106 @@ error: `#[label(bug = ...)]` is not a valid attribute LL | #[label(bug = "...")] | ^^^^^^^^^^^ | - = help: only `code`, `slug` and `applicability` are valid nested attributes + = help: first argument of the attribute should be the diagnostic slug error: `#[label("...")]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:91:9 | LL | #[label("...")] | ^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug error: `#[label(slug = ...)]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:100:9 | LL | #[label(slug = 4)] | ^^^^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug error: `#[label(slug(...))]` is not a valid attribute --> $DIR/subdiagnostic-derive.rs:109:9 | LL | #[label(slug("..."))] | ^^^^^^^^^^^ - -error: `#[label(slug)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:118:9 | -LL | #[label(slug)] - | ^^^^ + = help: first argument of the attribute should be the diagnostic slug -error: `slug` must be set in a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:127:1 +error: diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive.rs:128:1 | LL | #[label()] | ^^^^^^^^^^ error: `code` is not a valid nested attribute of a `label` attribute - --> $DIR/subdiagnostic-derive.rs:136:1 + --> $DIR/subdiagnostic-derive.rs:137:1 + | +LL | #[label(parser::add_paren, code = "...")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `applicability` is not a valid nested attribute of a `label` attribute + --> $DIR/subdiagnostic-derive.rs:146:1 | -LL | #[label(code = "...")] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[label(parser::add_paren, applicability = "machine-applicable")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:145:1 + --> $DIR/subdiagnostic-derive.rs:155:1 | LL | #[foo] | ^^^^^^ error: `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:159:5 + --> $DIR/subdiagnostic-derive.rs:169:5 | LL | #[bar] | ^^^^^^ error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:171:5 + --> $DIR/subdiagnostic-derive.rs:181:5 | LL | #[bar = "..."] | ^^^^^^^^^^^^^^ error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:183:5 + --> $DIR/subdiagnostic-derive.rs:193:5 | LL | #[bar = 4] | ^^^^^^^^^^ error: `#[bar("...")]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:195:11 + --> $DIR/subdiagnostic-derive.rs:205:11 | LL | #[bar("...")] | ^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug -error: `code` is not a valid nested attribute of a `label` attribute - --> $DIR/subdiagnostic-derive.rs:207:5 +error: diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive.rs:217:5 | LL | #[label(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:224:5 + --> $DIR/subdiagnostic-derive.rs:234:5 | LL | B { | ^ -error: the `#[primary_span]` attribute can only be applied to fields of type `Span` - --> $DIR/subdiagnostic-derive.rs:236:5 +error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/subdiagnostic-derive.rs:246:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: label without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:233:1 + --> $DIR/subdiagnostic-derive.rs:243:1 | -LL | / #[label(slug = "...")] +LL | / #[label(parser::add_paren)] LL | | -LL | | struct V { +LL | | struct W { LL | | #[primary_span] LL | | LL | | span: String, @@ -131,13 +139,13 @@ LL | | } | |_^ error: `#[applicability]` is only valid on suggestions - --> $DIR/subdiagnostic-derive.rs:246:5 + --> $DIR/subdiagnostic-derive.rs:256:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:256:5 + --> $DIR/subdiagnostic-derive.rs:266:5 | LL | #[bar] | ^^^^^^ @@ -145,21 +153,21 @@ LL | #[bar] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:267:5 + --> $DIR/subdiagnostic-derive.rs:277:5 | LL | #[bar = "..."] | ^^^^^^^^^^^^^^ error: `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:278:5 + --> $DIR/subdiagnostic-derive.rs:288:5 | LL | #[bar("...")] | ^^^^^^^^^^^^^ error: unexpected unsupported untagged union - --> $DIR/subdiagnostic-derive.rs:294:1 + --> $DIR/subdiagnostic-derive.rs:304:1 | -LL | / union AB { +LL | / union AC { LL | | LL | | span: u32, LL | | b: u64 @@ -167,95 +175,91 @@ LL | | } | |_^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:304:9 + --> $DIR/subdiagnostic-derive.rs:314:1 | -LL | #[label(slug = "label-ac-2")] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[label(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:301:9 + --> $DIR/subdiagnostic-derive.rs:311:1 | -LL | #[label(slug = "label-ac-1")] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[label(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:304:1 + --> $DIR/subdiagnostic-derive.rs:314:1 | -LL | #[label(slug = "label-ac-2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[label(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:301:1 + --> $DIR/subdiagnostic-derive.rs:311:1 | -LL | #[label(slug = "label-ac-1")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[label(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:313:30 +error: `#[label(parser::add_paren)]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:323:28 | -LL | #[label(slug = "label-ad-1", slug = "label-ad-2")] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[label(parser::add_paren, parser::add_paren)] + | ^^^^^^^^^^^^^^^^^ | -note: previously specified here - --> $DIR/subdiagnostic-derive.rs:313:9 - | -LL | #[label(slug = "label-ad-1", slug = "label-ad-2")] - | ^^^^^^^^^^^^^^^^^^^ + = help: a diagnostic slug must be the first argument to the attribute error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:327:5 + --> $DIR/subdiagnostic-derive.rs:336:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:324:5 + --> $DIR/subdiagnostic-derive.rs:333:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:333:8 + --> $DIR/subdiagnostic-derive.rs:342:8 | -LL | struct AF { +LL | struct AG { | ^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:370:42 + --> $DIR/subdiagnostic-derive.rs:379:47 | -LL | #[suggestion(slug = "...", code = "...", code = "...")] - | ^^^^^^^^^^^^ +LL | #[suggestion(parser::add_paren, code = "...", code = "...")] + | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:370:28 + --> $DIR/subdiagnostic-derive.rs:379:33 | -LL | #[suggestion(slug = "...", code = "...", code = "...")] - | ^^^^^^^^^^^^ +LL | #[suggestion(parser::add_paren, code = "...", code = "...")] + | ^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:388:5 + --> $DIR/subdiagnostic-derive.rs:397:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:385:5 + --> $DIR/subdiagnostic-derive.rs:394:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:399:5 + --> $DIR/subdiagnostic-derive.rs:408:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: suggestion without `applicability` - --> $DIR/subdiagnostic-derive.rs:394:1 + --> $DIR/subdiagnostic-derive.rs:403:1 | -LL | / #[suggestion(slug = "...", code = "...")] +LL | / #[suggestion(parser::add_paren, code = "...")] LL | | -LL | | struct AK { +LL | | struct AL { LL | | #[primary_span] ... | LL | | applicability: Span, @@ -263,22 +267,22 @@ LL | | } | |_^ error: suggestion without `applicability` - --> $DIR/subdiagnostic-derive.rs:405:1 + --> $DIR/subdiagnostic-derive.rs:414:1 | -LL | / #[suggestion(slug = "...", code = "...")] +LL | / #[suggestion(parser::add_paren, code = "...")] LL | | -LL | | struct AL { +LL | | struct AM { LL | | #[primary_span] LL | | span: Span, LL | | } | |_^ error: suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:413:1 + --> $DIR/subdiagnostic-derive.rs:422:1 | -LL | / #[suggestion(slug = "...")] +LL | / #[suggestion(parser::add_paren)] LL | | -LL | | struct AM { +LL | | struct AN { LL | | #[primary_span] ... | LL | | applicability: Applicability, @@ -286,50 +290,50 @@ LL | | } | |_^ error: invalid applicability - --> $DIR/subdiagnostic-derive.rs:423:41 + --> $DIR/subdiagnostic-derive.rs:432:46 | -LL | #[suggestion(slug = "...", code ="...", applicability = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^ error: suggestion without `applicability` - --> $DIR/subdiagnostic-derive.rs:441:1 + --> $DIR/subdiagnostic-derive.rs:450:1 | -LL | / #[suggestion(slug = "...", code = "...")] +LL | / #[suggestion(parser::add_paren, code = "...")] LL | | LL | | -LL | | struct AQ { +LL | | struct AR { LL | | var: String, LL | | } | |_^ error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:441:1 + --> $DIR/subdiagnostic-derive.rs:450:1 | -LL | / #[suggestion(slug = "...", code = "...")] +LL | / #[suggestion(parser::add_paren, code = "...")] LL | | LL | | -LL | | struct AQ { +LL | | struct AR { LL | | var: String, LL | | } | |_^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:456:1 + --> $DIR/subdiagnostic-derive.rs:465:1 | LL | #[label] | ^^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:476:34 + --> $DIR/subdiagnostic-derive.rs:485:39 | -LL | #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")] - | ^^^^^^^ +LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] + | ^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:495:38 + --> $DIR/subdiagnostic-derive.rs:504:43 | -LL | #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")] - | ^^^^^^^ +LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] + | ^^^^^^^ error: cannot find attribute `foo` in this scope --> $DIR/subdiagnostic-derive.rs:63:3 @@ -338,52 +342,59 @@ LL | #[foo] | ^^^ error: cannot find attribute `foo` in this scope - --> $DIR/subdiagnostic-derive.rs:145:3 + --> $DIR/subdiagnostic-derive.rs:155:3 | LL | #[foo] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:159:7 + --> $DIR/subdiagnostic-derive.rs:169:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:171:7 + --> $DIR/subdiagnostic-derive.rs:181:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:183:7 + --> $DIR/subdiagnostic-derive.rs:193:7 | LL | #[bar = 4] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:195:7 + --> $DIR/subdiagnostic-derive.rs:205:7 | LL | #[bar("...")] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:256:7 + --> $DIR/subdiagnostic-derive.rs:266:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:267:7 + --> $DIR/subdiagnostic-derive.rs:277:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:278:7 + --> $DIR/subdiagnostic-derive.rs:288:7 | LL | #[bar("...")] | ^^^ -error: aborting due to 51 previous errors +error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` + --> $DIR/subdiagnostic-derive.rs:118:9 + | +LL | #[label(slug)] + | ^^^^ not found in `rustc_errors::fluent` + +error: aborting due to 52 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/abi/rustcall-generic.rs b/src/test/ui/abi/rustcall-generic.rs index 2fa41a7e35a74..411c98e10313d 100644 --- a/src/test/ui/abi/rustcall-generic.rs +++ b/src/test/ui/abi/rustcall-generic.rs @@ -1,4 +1,7 @@ +// revisions: normal opt // check-pass +//[opt] compile-flags: -Zmir-opt-level=3 + #![feature(unboxed_closures)] extern "rust-call" fn foo<T>(_: T) {} diff --git a/src/test/ui/aligned_enum_cast.rs b/src/test/ui/aligned_enum_cast.rs index 4b5776a6aa8ee..1ddf127172e65 100644 --- a/src/test/ui/aligned_enum_cast.rs +++ b/src/test/ui/aligned_enum_cast.rs @@ -11,5 +11,15 @@ enum Aligned { fn main() { let aligned = Aligned::Zero; let fo = aligned as u8; - println!("foo {}",fo); + println!("foo {}", fo); + assert_eq!(fo, 0); + println!("{}", tou8(Aligned::Zero)); + assert_eq!(tou8(Aligned::Zero), 0); +} + +#[inline(never)] +fn tou8(al: Aligned) -> u8 { + // Cast behind a function call so ConstProp does not see it + // (so that we can test codegen). + al as u8 } diff --git a/src/test/ui/argument-suggestions/basic.stderr b/src/test/ui/argument-suggestions/basic.stderr index dd4812b5b2589..c495ad6b842f8 100644 --- a/src/test/ui/argument-suggestions/basic.stderr +++ b/src/test/ui/argument-suggestions/basic.stderr @@ -16,7 +16,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/basic.rs:21:5 | LL | extra(""); - | ^^^^^ -- argument unexpected + | ^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/basic.rs:14:4 diff --git a/src/test/ui/argument-suggestions/exotic-calls.rs b/src/test/ui/argument-suggestions/exotic-calls.rs new file mode 100644 index 0000000000000..a18e967668def --- /dev/null +++ b/src/test/ui/argument-suggestions/exotic-calls.rs @@ -0,0 +1,26 @@ +fn foo<T: Fn()>(t: T) { + t(1i32); + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn bar(t: impl Fn()) { + t(1i32); + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn baz() -> impl Fn() { + || {} +} + +fn baz2() { + baz()(1i32) + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn qux() { + let x = || {}; + x(1i32); + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn main() {} diff --git a/src/test/ui/argument-suggestions/exotic-calls.stderr b/src/test/ui/argument-suggestions/exotic-calls.stderr new file mode 100644 index 0000000000000..ca93ecc4e381a --- /dev/null +++ b/src/test/ui/argument-suggestions/exotic-calls.stderr @@ -0,0 +1,67 @@ +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:2:5 + | +LL | t(1i32); + | ^ ---- argument of type `i32` unexpected + | +note: callable defined here + --> $DIR/exotic-calls.rs:1:11 + | +LL | fn foo<T: Fn()>(t: T) { + | ^^^^ +help: remove the extra argument + | +LL | t(); + | ~~~ + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:7:5 + | +LL | t(1i32); + | ^ ---- argument of type `i32` unexpected + | +note: type parameter defined here + --> $DIR/exotic-calls.rs:6:11 + | +LL | fn bar(t: impl Fn()) { + | ^^^^^^^^^ +help: remove the extra argument + | +LL | t(); + | ~~~ + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:16:5 + | +LL | baz()(1i32) + | ^^^^^ ---- argument of type `i32` unexpected + | +note: opaque type defined here + --> $DIR/exotic-calls.rs:11:13 + | +LL | fn baz() -> impl Fn() { + | ^^^^^^^^^ +help: remove the extra argument + | +LL | baz()() + | + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:22:5 + | +LL | x(1i32); + | ^ ---- argument of type `i32` unexpected + | +note: closure defined here + --> $DIR/exotic-calls.rs:21:13 + | +LL | let x = || {}; + | ^^ +help: remove the extra argument + | +LL | x(); + | ~~~ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0057`. diff --git a/src/test/ui/argument-suggestions/extra_arguments.stderr b/src/test/ui/argument-suggestions/extra_arguments.stderr index 9b63f9bcbfae4..32b1e15737ab9 100644 --- a/src/test/ui/argument-suggestions/extra_arguments.stderr +++ b/src/test/ui/argument-suggestions/extra_arguments.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/extra_arguments.rs:7:3 | LL | empty(""); - | ^^^^^ -- argument unexpected + | ^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:1:4 @@ -18,7 +18,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:9:3 | LL | one_arg(1, 1); - | ^^^^^^^ - argument unexpected + | ^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -34,7 +34,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:10:3 | LL | one_arg(1, ""); - | ^^^^^^^ -- argument unexpected + | ^^^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -50,9 +50,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:11:3 | LL | one_arg(1, "", 1.0); - | ^^^^^^^ -- --- argument unexpected + | ^^^^^^^ -- --- argument of type `{float}` unexpected | | - | argument unexpected + | argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -68,7 +68,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:13:3 | LL | two_arg_same(1, 1, 1); - | ^^^^^^^^^^^^ - argument unexpected + | ^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -84,7 +84,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:14:3 | LL | two_arg_same(1, 1, 1.0); - | ^^^^^^^^^^^^ --- argument unexpected + | ^^^^^^^^^^^^ --- argument of type `{float}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -100,7 +100,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:16:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - argument of type `&str` unexpected + | ^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -116,7 +116,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:17:3 | LL | two_arg_diff(1, "", ""); - | ^^^^^^^^^^^^ -- argument unexpected + | ^^^^^^^^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -132,9 +132,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:18:3 | LL | two_arg_diff(1, 1, "", ""); - | ^^^^^^^^^^^^ - -- argument unexpected + | ^^^^^^^^^^^^ - -- argument of type `&'static str` unexpected | | - | argument of type `&str` unexpected + | argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -150,9 +150,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:19:3 | LL | two_arg_diff(1, "", 1, ""); - | ^^^^^^^^^^^^ - -- argument unexpected + | ^^^^^^^^^^^^ - -- argument of type `&'static str` unexpected | | - | argument unexpected + | argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -168,7 +168,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:22:3 | LL | two_arg_same(1, 1, ""); - | ^^^^^^^^^^^^ -- argument unexpected + | ^^^^^^^^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -184,7 +184,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:23:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - argument of type `&str` unexpected + | ^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -203,7 +203,7 @@ LL | two_arg_same( | ^^^^^^^^^^^^ ... LL | "" - | -- argument unexpected + | -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -222,7 +222,7 @@ LL | two_arg_diff( | ^^^^^^^^^^^^ LL | 1, LL | 1, - | - argument of type `&str` unexpected + | - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 diff --git a/src/test/ui/argument-suggestions/issue-97484.stderr b/src/test/ui/argument-suggestions/issue-97484.stderr index 2af24d521f380..9589e919c0a1f 100644 --- a/src/test/ui/argument-suggestions/issue-97484.stderr +++ b/src/test/ui/argument-suggestions/issue-97484.stderr @@ -2,21 +2,20 @@ error[E0061]: this function takes 4 arguments but 7 arguments were supplied --> $DIR/issue-97484.rs:12:5 | LL | foo(&&A, B, C, D, E, F, G); - | ^^^ - - - argument unexpected + | ^^^ - - - argument of type `F` unexpected | | | - | | argument of type `&E` unexpected - | argument of type `D` unexpected + | | argument of type `C` unexpected + | argument of type `B` unexpected | note: function defined here --> $DIR/issue-97484.rs:9:4 | LL | fn foo(a: &A, d: D, e: &E, g: G) {} | ^^^ ----- ---- ----- ---- -help: consider removing the `` - | -LL - foo(&&A, B, C, D, E, F, G); -LL + foo(&&A, B, C, D, E, F, G); +help: consider borrowing here | +LL | foo(&&A, B, C, D, &E, F, G); + | ~~ help: remove the extra arguments | LL | foo(&&A, D, /* &E */, G); diff --git a/src/test/ui/argument-suggestions/mixed_cases.stderr b/src/test/ui/argument-suggestions/mixed_cases.stderr index 3fe4473a594e0..a52a30d7884f8 100644 --- a/src/test/ui/argument-suggestions/mixed_cases.stderr +++ b/src/test/ui/argument-suggestions/mixed_cases.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/mixed_cases.rs:10:3 | LL | two_args(1, "", X {}); - | ^^^^^^^^ -- ---- argument unexpected + | ^^^^^^^^ -- ---- argument of type `X` unexpected | | | expected `f32`, found `&str` | @@ -20,9 +20,9 @@ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/mixed_cases.rs:11:3 | LL | three_args(1, "", X {}, ""); - | ^^^^^^^^^^ -- ---- -- argument unexpected + | ^^^^^^^^^^ -- ---- -- argument of type `&'static str` unexpected | | | - | | argument of type `&str` unexpected + | | argument of type `X` unexpected | an argument of type `f32` is missing | note: function defined here @@ -58,7 +58,7 @@ error[E0308]: arguments to this function are incorrect --> $DIR/mixed_cases.rs:17:3 | LL | three_args(1, "", X {}); - | ^^^^^^^^^^ -- ---- argument of type `&str` unexpected + | ^^^^^^^^^^ -- ---- argument of type `X` unexpected | | | an argument of type `f32` is missing | diff --git a/src/test/ui/array-slice-vec/array_const_index-0.stderr b/src/test/ui/array-slice-vec/array_const_index-0.stderr index 641705e1c6875..4832398713dbe 100644 --- a/src/test/ui/array-slice-vec/array_const_index-0.stderr +++ b/src/test/ui/array-slice-vec/array_const_index-0.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/array_const_index-0.rs:2:16 | LL | const B: i32 = (&A)[1]; - | ---------------^^^^^^^- - | | - | index out of bounds: the length is 0 but the index is 1 + | ------------ ^^^^^^^ index out of bounds: the length is 0 but the index is 1 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const B: i32 = (&A)[1]; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/array_const_index-0.rs:2:16 + | +LL | const B: i32 = (&A)[1]; + | ------------ ^^^^^^^ index out of bounds: the length is 0 but the index is 1 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/array-slice-vec/array_const_index-1.stderr b/src/test/ui/array-slice-vec/array_const_index-1.stderr index 4d52d38af5e17..361f518c052f0 100644 --- a/src/test/ui/array-slice-vec/array_const_index-1.stderr +++ b/src/test/ui/array-slice-vec/array_const_index-1.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/array_const_index-1.rs:2:16 | LL | const B: i32 = A[1]; - | ---------------^^^^- - | | - | index out of bounds: the length is 0 but the index is 1 + | ------------ ^^^^ index out of bounds: the length is 0 but the index is 1 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const B: i32 = A[1]; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/array_const_index-1.rs:2:16 + | +LL | const B: i32 = A[1]; + | ------------ ^^^^ index out of bounds: the length is 0 but the index is 1 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/array-slice-vec/infer_array_len.stderr b/src/test/ui/array-slice-vec/infer_array_len.stderr index 8da6d97251ba1..919550cac3087 100644 --- a/src/test/ui/array-slice-vec/infer_array_len.stderr +++ b/src/test/ui/array-slice-vec/infer_array_len.stderr @@ -4,7 +4,6 @@ error[E0282]: type annotations needed LL | let [_, _] = a.into(); | ^^^^^^ | - = note: type must be known at this point help: consider giving this pattern a type | LL | let [_, _]: _ = a.into(); diff --git a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr index 20a5b99845bbc..70a4cbebeee98 100644 --- a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr +++ b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr @@ -27,8 +27,6 @@ error[E0282]: type annotations needed | LL | [] => {} | ^^ cannot infer type - | - = note: type must be known at this point error: aborting due to 5 previous errors diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs index 040d4df546fb5..dbb6cbb9437b5 100644 --- a/src/test/ui/asm/aarch64/srcloc.rs +++ b/src/test/ui/asm/aarch64/srcloc.rs @@ -118,5 +118,12 @@ fn main() { //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic //~^^^^^^^ ERROR: unrecognized instruction mnemonic //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "", + "\n", + "invalid_instruction" + ); + //~^^ ERROR: unrecognized instruction mnemonic } } diff --git a/src/test/ui/asm/aarch64/srcloc.stderr b/src/test/ui/asm/aarch64/srcloc.stderr index f8b645c23f5a0..2e17b60b91243 100644 --- a/src/test/ui/asm/aarch64/srcloc.stderr +++ b/src/test/ui/asm/aarch64/srcloc.stderr @@ -274,5 +274,17 @@ note: instantiated into assembly here LL | invalid_instruction4 | ^ -error: aborting due to 23 previous errors +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:125:14 + | +LL | "invalid_instruction" + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction + | ^ + +error: aborting due to 24 previous errors diff --git a/src/test/ui/asm/aarch64/type-check-2-2.rs b/src/test/ui/asm/aarch64/type-check-2-2.rs index e4d29754556c8..aa12d4aa4b40c 100644 --- a/src/test/ui/asm/aarch64/type-check-2-2.rs +++ b/src/test/ui/asm/aarch64/type-check-2-2.rs @@ -17,10 +17,10 @@ fn main() { let x: u64; asm!("{}", in(reg) x); - //~^ ERROR use of possibly-uninitialized variable: `x` + //~^ ERROR used binding `x` isn't initialized let mut y: u64; asm!("{}", inout(reg) y); - //~^ ERROR use of possibly-uninitialized variable: `y` + //~^ ERROR used binding `y` isn't initialized let _ = y; // Outputs require mutable places diff --git a/src/test/ui/asm/aarch64/type-check-2-2.stderr b/src/test/ui/asm/aarch64/type-check-2-2.stderr index 37bbe394994e0..b2a695529f948 100644 --- a/src/test/ui/asm/aarch64/type-check-2-2.stderr +++ b/src/test/ui/asm/aarch64/type-check-2-2.stderr @@ -1,14 +1,18 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/type-check-2-2.rs:19:28 | +LL | let x: u64; + | - binding declared here but left uninitialized LL | asm!("{}", in(reg) x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `y` +error[E0381]: used binding `y` isn't initialized --> $DIR/type-check-2-2.rs:22:9 | +LL | let mut y: u64; + | ----- binding declared here but left uninitialized LL | asm!("{}", inout(reg) y); - | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/type-check-2-2.rs:30:29 diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr index 4b99652cd20bd..875df44ffab78 100644 --- a/src/test/ui/asm/aarch64/type-check-2.stderr +++ b/src/test/ui/asm/aarch64/type-check-2.stderr @@ -22,7 +22,7 @@ LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:41:28: 41:38]` for inline assembly +error: cannot use value of type `[closure@$DIR/type-check-2.rs:41:28: 41:36]` for inline assembly --> $DIR/type-check-2.rs:41:28 | LL | asm!("{}", in(reg) |x: i32| x); diff --git a/src/test/ui/asm/issue-99071.rs b/src/test/ui/asm/issue-99071.rs new file mode 100644 index 0000000000000..bb6201861dff6 --- /dev/null +++ b/src/test/ui/asm/issue-99071.rs @@ -0,0 +1,21 @@ +// compile-flags: --target thumbv6m-none-eabi +// needs-llvm-components: arm +// needs-asm-support + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] +#![crate_type = "rlib"] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +pub fn foo() { + unsafe { + asm!("", in("r8") 0); + //~^ cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code + } +} diff --git a/src/test/ui/asm/issue-99071.stderr b/src/test/ui/asm/issue-99071.stderr new file mode 100644 index 0000000000000..47386ffa4a8c9 --- /dev/null +++ b/src/test/ui/asm/issue-99071.stderr @@ -0,0 +1,8 @@ +error: cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code + --> $DIR/issue-99071.rs:18:18 + | +LL | asm!("", in("r8") 0); + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/asm/issue-99122-2.rs b/src/test/ui/asm/issue-99122-2.rs new file mode 100644 index 0000000000000..cfb9fd90a55b7 --- /dev/null +++ b/src/test/ui/asm/issue-99122-2.rs @@ -0,0 +1,21 @@ +// check-pass +// needs-asm-support +// only-x86_64 + +// This demonstrates why we need to erase regions before sized check in intrinsicck + +struct NoCopy; + +struct Wrap<'a, T, Tail: ?Sized>(&'a T, Tail); + +pub unsafe fn test() { + let i = NoCopy; + let j = Wrap(&i, ()); + let pointer = &j as *const _; + core::arch::asm!( + "nop", + in("eax") pointer, + ); +} + +fn main() {} diff --git a/src/test/ui/asm/issue-99122.rs b/src/test/ui/asm/issue-99122.rs new file mode 100644 index 0000000000000..744a563d3d147 --- /dev/null +++ b/src/test/ui/asm/issue-99122.rs @@ -0,0 +1,13 @@ +// needs-asm-support +// only-x86_64 + +pub unsafe fn test() { + let pointer = 1u32 as *const _; + //~^ ERROR cannot cast to a pointer of an unknown kind + core::arch::asm!( + "nop", + in("eax") pointer, + ); +} + +fn main() {} diff --git a/src/test/ui/asm/issue-99122.stderr b/src/test/ui/asm/issue-99122.stderr new file mode 100644 index 0000000000000..2758a4ac4377e --- /dev/null +++ b/src/test/ui/asm/issue-99122.stderr @@ -0,0 +1,11 @@ +error[E0641]: cannot cast to a pointer of an unknown kind + --> $DIR/issue-99122.rs:5:27 + | +LL | let pointer = 1u32 as *const _; + | ^^^^^^^^ needs more type information + | + = note: the type information given here is insufficient to check whether the pointer cast is valid + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0641`. diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index 5a997b47d73eb..162ff1d32bc44 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -33,33 +33,6 @@ LL | asm!("{}", sym x); | = help: `sym` operands must refer to either a function or a static -error[E0308]: mismatched types - --> $DIR/type-check-1.rs:58:26 - | -LL | asm!("{}", const 0f32); - | ^^^^ expected integer, found `f32` - -error[E0308]: mismatched types - --> $DIR/type-check-1.rs:60:26 - | -LL | asm!("{}", const 0 as *mut u8); - | ^^^^^^^^^^^^ expected integer, found *-ptr - | - = note: expected type `{integer}` - found raw pointer `*mut u8` - -error[E0308]: mismatched types - --> $DIR/type-check-1.rs:62:26 - | -LL | asm!("{}", const &0); - | ^^ expected integer, found `&{integer}` - | -help: consider removing the borrow - | -LL - asm!("{}", const &0); -LL + asm!("{}", const 0); - | - error: invalid asm output --> $DIR/type-check-1.rs:15:29 | @@ -123,6 +96,33 @@ LL | asm!("{}", inout(reg) v[..]); | = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:58:26 + | +LL | asm!("{}", const 0f32); + | ^^^^ expected integer, found `f32` + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:60:26 + | +LL | asm!("{}", const 0 as *mut u8); + | ^^^^^^^^^^^^ expected integer, found *-ptr + | + = note: expected type `{integer}` + found raw pointer `*mut u8` + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:62:26 + | +LL | asm!("{}", const &0); + | ^^ expected integer, found `&{integer}` + | +help: consider removing the borrow + | +LL - asm!("{}", const &0); +LL + asm!("{}", const 0); + | + error[E0308]: mismatched types --> $DIR/type-check-1.rs:76:25 | diff --git a/src/test/ui/asm/x86_64/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs index 8a21d75977212..1135ad2e1c643 100644 --- a/src/test/ui/asm/x86_64/srcloc.rs +++ b/src/test/ui/asm/x86_64/srcloc.rs @@ -120,5 +120,12 @@ fn main() { //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' + + asm!( + "", + "\n", + "invalid_instruction" + ); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' } } diff --git a/src/test/ui/asm/x86_64/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr index b62c8948289dd..8899c1b916bd0 100644 --- a/src/test/ui/asm/x86_64/srcloc.stderr +++ b/src/test/ui/asm/x86_64/srcloc.stderr @@ -286,5 +286,17 @@ note: instantiated into assembly here LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 23 previous errors; 1 warning emitted +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:127:14 + | +LL | "invalid_instruction" + | ^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr index 46baeb511ca77..d9ca25519dc8a 100644 --- a/src/test/ui/asm/x86_64/type-check-2.stderr +++ b/src/test/ui/asm/x86_64/type-check-2.stderr @@ -30,7 +30,7 @@ LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:52:28: 52:38]` for inline assembly +error: cannot use value of type `[closure@$DIR/type-check-2.rs:52:28: 52:36]` for inline assembly --> $DIR/type-check-2.rs:52:28 | LL | asm!("{}", in(reg) |x: i32| x); diff --git a/src/test/ui/asm/x86_64/type-check-5.rs b/src/test/ui/asm/x86_64/type-check-5.rs index 474478f6a88e1..6190e0b52f4e9 100644 --- a/src/test/ui/asm/x86_64/type-check-5.rs +++ b/src/test/ui/asm/x86_64/type-check-5.rs @@ -13,10 +13,10 @@ fn main() { let x: u64; asm!("{}", in(reg) x); - //~^ ERROR use of possibly-uninitialized variable: `x` + //~^ ERROR E0381 let mut y: u64; asm!("{}", inout(reg) y); - //~^ ERROR use of possibly-uninitialized variable: `y` + //~^ ERROR E0381 let _ = y; // Outputs require mutable places diff --git a/src/test/ui/asm/x86_64/type-check-5.stderr b/src/test/ui/asm/x86_64/type-check-5.stderr index 181ecaf585585..e9c93fea561a8 100644 --- a/src/test/ui/asm/x86_64/type-check-5.stderr +++ b/src/test/ui/asm/x86_64/type-check-5.stderr @@ -1,14 +1,18 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/type-check-5.rs:15:28 | +LL | let x: u64; + | - binding declared here but left uninitialized LL | asm!("{}", in(reg) x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `y` +error[E0381]: used binding `y` isn't initialized --> $DIR/type-check-5.rs:18:9 | +LL | let mut y: u64; + | ----- binding declared here but left uninitialized LL | asm!("{}", inout(reg) y); - | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable --> $DIR/type-check-5.rs:26:29 diff --git a/src/test/ui/associated-consts/assoc-const-ty-mismatch.stderr b/src/test/ui/associated-consts/assoc-const-ty-mismatch.stderr index 703245145ce4e..58a8aceca2f24 100644 --- a/src/test/ui/associated-consts/assoc-const-ty-mismatch.stderr +++ b/src/test/ui/associated-consts/assoc-const-ty-mismatch.stderr @@ -8,7 +8,7 @@ note: associated constant defined here does not match type --> $DIR/assoc-const-ty-mismatch.rs:5:3 | LL | const N: usize; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: mismatch in bind of associated type, got const --> $DIR/assoc-const-ty-mismatch.rs:25:18 @@ -20,7 +20,7 @@ note: associated type defined here does not match const --> $DIR/assoc-const-ty-mismatch.rs:9:3 | LL | type T; - | ^^^^^^^ + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr index 60cf9a533cd72..5435f22321c92 100644 --- a/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr @@ -8,12 +8,12 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:10:5 | LL | const ID: i32 = 1; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:14:5 | LL | const ID: i32 = 3; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: disambiguate the associated constant for candidate #1 | LL | const X: i32 = <i32 as Foo>::ID; diff --git a/src/test/ui/associated-consts/associated-const-dead-code.stderr b/src/test/ui/associated-consts/associated-const-dead-code.stderr index 7a4dbfe087b5a..cc701cc4b9424 100644 --- a/src/test/ui/associated-consts/associated-const-dead-code.stderr +++ b/src/test/ui/associated-consts/associated-const-dead-code.stderr @@ -1,8 +1,8 @@ error: associated constant `BAR` is never used - --> $DIR/associated-const-dead-code.rs:6:5 + --> $DIR/associated-const-dead-code.rs:6:11 | LL | const BAR: u32 = 1; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^ | note: the lint level is defined here --> $DIR/associated-const-dead-code.rs:1:9 diff --git a/src/test/ui/associated-consts/associated-const-private-impl.stderr b/src/test/ui/associated-consts/associated-const-private-impl.stderr index aa356c596f8a0..a3fa3002e1efb 100644 --- a/src/test/ui/associated-consts/associated-const-private-impl.stderr +++ b/src/test/ui/associated-consts/associated-const-private-impl.stderr @@ -2,7 +2,7 @@ error[E0624]: associated constant `ID` is private --> $DIR/associated-const-private-impl.rs:13:30 | LL | const ID: i32 = 1; - | ------------------ private associated constant defined here + | ------------- private associated constant defined here ... LL | assert_eq!(1, bar1::Foo::ID); | ^^ private associated constant diff --git a/src/test/ui/associated-consts/defaults-cyclic-fail.stderr b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr index c4cd9c2a49fd7..582473905cfdd 100644 --- a/src/test/ui/associated-consts/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr @@ -2,13 +2,13 @@ error[E0391]: cycle detected when const-evaluating + checking `Tr::A` --> $DIR/defaults-cyclic-fail.rs:5:5 | LL | const A: u8 = Self::B; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | note: ...which requires const-evaluating + checking `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle note: cycle used when const-evaluating + checking `main::promoted[1]` --> $DIR/defaults-cyclic-fail.rs:16:16 diff --git a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr index 7406b2ddee9b2..66ee6031c7156 100644 --- a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr +++ b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/defaults-not-assumed-fail.rs:8:19 | LL | const B: u8 = Self::A + 1; - | --------------^^^^^^^^^^^- - | | - | attempt to compute `u8::MAX + 1_u8`, which would overflow + | ----------- ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -29,3 +27,26 @@ LL | assert_eq!(<() as Tr>::B, 0); // causes the error above error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/defaults-not-assumed-fail.rs:8:19 + | +LL | const B: u8 = Self::A + 1; + | ----------- ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: erroneous constant used + --> $DIR/defaults-not-assumed-fail.rs:34:5 + | +LL | assert_eq!(<() as Tr>::B, 0); // causes the error above + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index b4dc730d8631f..51a50cfdaf981 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR` +error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR` --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:22 | LL | const BAR: u32 = IMPL_REF_BAR; @@ -8,23 +8,23 @@ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`... + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires caching mir of `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR` for CTFE... + | ^^^^^^^^^^^^^^ +note: ...which requires caching mir of `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR` for CTFE... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`, completing the cycle + | ^^^^^^^^^^^^^^ + = note: ...which again requires elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index 97ede6ad388f2..b9d1808feb367 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -8,22 +8,22 @@ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ note: ...which requires caching mir of `FooDefault::BAR` for CTFE... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ = note: ...which again requires elaborating drops for `FooDefault::BAR`, completing the cycle = note: cycle used when running analysis passes on this crate diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index bd97c31229ecc..271e69206cd7a 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR` +error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:22 | LL | const BAR: u32 = TRAIT_REF_BAR; @@ -8,23 +8,23 @@ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`... + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires caching mir of `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR` for CTFE... + | ^^^^^^^^^^^^^^ +note: ...which requires caching mir of `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR` for CTFE... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`, completing the cycle + | ^^^^^^^^^^^^^^ + = note: ...which again requires elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr b/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr index ea475ffc5547a..f4efd131248ce 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names-2.stderr @@ -2,9 +2,9 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/associated-item-duplicate-names-2.rs:5:5 | LL | const bar: bool = true; - | ----------------------- previous definition of `bar` here + | --------------- previous definition of `bar` here LL | fn bar() {} - | ^^^^^^^^^^^ duplicate definition + | ^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr index 57495863c9891..03782f6634800 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -2,9 +2,9 @@ error[E0201]: duplicate definitions with name `Bar`: --> $DIR/associated-item-duplicate-names-3.rs:14:5 | LL | type Bar = i16; - | --------------- previous definition of `Bar` here + | -------- previous definition of `Bar` here LL | type Bar = u16; - | ^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/associated-item/associated-item-duplicate-names.stderr b/src/test/ui/associated-item/associated-item-duplicate-names.stderr index f4af9e0293950..c9119c1027111 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names.stderr @@ -2,17 +2,17 @@ error[E0201]: duplicate definitions with name `Ty`: --> $DIR/associated-item-duplicate-names.rs:11:5 | LL | type Ty = (); - | ------------- previous definition of `Ty` here + | ------- previous definition of `Ty` here LL | type Ty = usize; - | ^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `BAR`: --> $DIR/associated-item-duplicate-names.rs:13:5 | LL | const BAR: u32 = 7; - | ------------------- previous definition of `BAR` here + | -------------- previous definition of `BAR` here LL | const BAR: u32 = 8; - | ^^^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^ duplicate definition error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-item/associated-item-enum.stderr b/src/test/ui/associated-item/associated-item-enum.stderr index d52b2b36c7bcc..ebf3c5499a68b 100644 --- a/src/test/ui/associated-item/associated-item-enum.stderr +++ b/src/test/ui/associated-item/associated-item-enum.stderr @@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `mispellable` found for enum ` --> $DIR/associated-item-enum.rs:17:11 | LL | enum Enum { Variant } - | --------- variant or associated item `mispellable` not found here + | --------- variant or associated item `mispellable` not found for this enum ... LL | Enum::mispellable(); | ^^^^^^^^^^^ @@ -14,7 +14,7 @@ error[E0599]: no variant or associated item named `mispellable_trait` found for --> $DIR/associated-item-enum.rs:18:11 | LL | enum Enum { Variant } - | --------- variant or associated item `mispellable_trait` not found here + | --------- variant or associated item `mispellable_trait` not found for this enum ... LL | Enum::mispellable_trait(); | ^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ error[E0599]: no variant or associated item named `MISPELLABLE` found for enum ` --> $DIR/associated-item-enum.rs:19:11 | LL | enum Enum { Variant } - | --------- variant or associated item `MISPELLABLE` not found here + | --------- variant or associated item `MISPELLABLE` not found for this enum ... LL | Enum::MISPELLABLE; | ^^^^^^^^^^^ diff --git a/src/test/ui/associated-item/issue-48027.stderr b/src/test/ui/associated-item/issue-48027.stderr index 9ae25a8c22220..5487af1a835d8 100644 --- a/src/test/ui/associated-item/issue-48027.stderr +++ b/src/test/ui/associated-item/issue-48027.stderr @@ -1,15 +1,3 @@ -error[E0283]: type annotations needed - --> $DIR/issue-48027.rs:3:32 - | -LL | fn return_n(&self) -> [u8; Bar::X]; - | ^^^^^^ - | | - | cannot infer type - | help: use the fully qualified path to an implementation: `<Type as Bar>::X` - | - = note: cannot satisfy `_: Bar` - = note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` - error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/issue-48027.rs:6:6 | @@ -25,6 +13,18 @@ LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait +error[E0283]: type annotations needed + --> $DIR/issue-48027.rs:3:32 + | +LL | fn return_n(&self) -> [u8; Bar::X]; + | ^^^^^^ + | | + | cannot infer type + | help: use the fully qualified path to an implementation: `<Type as Bar>::X` + | + = note: cannot satisfy `_: Bar` + = note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl` + error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0283. diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs index 67b97c21805e6..4c36289f47b85 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs @@ -30,7 +30,7 @@ impl Thing for AssocNoCopy { type Out = Box<dyn Bar<Assoc: Copy>>; fn func() -> Self::Out { - Box::new(AssocNoCopy) //~^ ERROR the trait bound `String: Copy` is not satisfied + Box::new(AssocNoCopy) } } diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr index f1dcd34066dbc..a32ab453152a0 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -1,10 +1,8 @@ error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:33:9 + --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18 | -LL | Box::new(AssocNoCopy) - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` - | - = note: required for the cast to the object type `dyn Bar<Assoc = <AssocNoCopy as Thing>::Out::{opaque#0}>` +LL | fn func() -> Self::Out { + | ^^^^^^^^^ the trait `Copy` is not implemented for `String` error: aborting due to previous error diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index e1dc6f8f4b63d..6e464f69510ec 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -1,8 +1,8 @@ #![feature(associated_type_bounds)] #![feature(type_alias_impl_trait)] -#![feature(untagged_unions)] use std::iter; +use std::mem::ManuallyDrop; struct SI1<T: Iterator<Item: Copy, Item: Send>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] @@ -74,36 +74,36 @@ where union UI1<T: Iterator<Item: Copy, Item: Send>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop<T>, } union UI2<T: Iterator<Item: Copy, Item: Copy>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop<T>, } union UI3<T: Iterator<Item: 'static, Item: 'static>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop<T>, } union UW1<T> where T: Iterator<Item: Copy, Item: Send>, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop<T>, } union UW2<T> where T: Iterator<Item: Copy, Item: Copy>, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop<T>, } union UW3<T> where T: Iterator<Item: 'static, Item: 'static>, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop<T>, } fn FI1<T: Iterator<Item: Copy, Item: Send>>() {} diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs index 5af057387509d..f26037f070766 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.rs +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -1,5 +1,6 @@ #![feature(associated_type_bounds)] -#![feature(untagged_unions)] + +use std::mem::ManuallyDrop; struct S1 { f: dyn Iterator<Item: Copy> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions @@ -17,12 +18,12 @@ enum E3 { V(dyn Iterator<Item: 'static>) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` -union U1 { f: dyn Iterator<Item: Copy> } +union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` -union U2 { f: Box<dyn Iterator<Item: Copy>> } +union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -union U3 { f: dyn Iterator<Item: 'static> } +union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr index 0cacd78724732..978390fa71235 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.stderr +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -1,59 +1,59 @@ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:4:29 + --> $DIR/inside-adt.rs:5:29 | LL | struct S1 { f: dyn Iterator<Item: Copy> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:6:33 + --> $DIR/inside-adt.rs:7:33 | LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:8:29 + --> $DIR/inside-adt.rs:9:29 | LL | struct S3 { f: dyn Iterator<Item: 'static> } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:11:26 + --> $DIR/inside-adt.rs:12:26 | LL | enum E1 { V(dyn Iterator<Item: Copy>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:14:30 + --> $DIR/inside-adt.rs:15:30 | LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:16:26 + --> $DIR/inside-adt.rs:17:26 | LL | enum E3 { V(dyn Iterator<Item: 'static>) } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:20:28 + --> $DIR/inside-adt.rs:21:41 | -LL | union U1 { f: dyn Iterator<Item: Copy> } - | ^^^^^^^^^^ +LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> } + | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:23:32 + --> $DIR/inside-adt.rs:24:45 | -LL | union U2 { f: Box<dyn Iterator<Item: Copy>> } - | ^^^^^^^^^^ +LL | union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> } + | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:25:28 + --> $DIR/inside-adt.rs:26:41 | -LL | union U3 { f: dyn Iterator<Item: 'static> } - | ^^^^^^^^^^^^^ +LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> } + | ^^^^^^^^^^^^^ error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:11:13 + --> $DIR/inside-adt.rs:12:13 | LL | enum E1 { V(dyn Iterator<Item: Copy>) } | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -71,7 +71,7 @@ LL | enum E1 { V(Box<dyn Iterator<Item: Copy>>) } | ++++ + error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:16:13 + --> $DIR/inside-adt.rs:17:13 | LL | enum E3 { V(dyn Iterator<Item: 'static>) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -89,40 +89,42 @@ LL | enum E3 { V(Box<dyn Iterator<Item: 'static>>) } | ++++ + error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:20:15 + --> $DIR/inside-adt.rs:21:15 | -LL | union U1 { f: dyn Iterator<Item: Copy> } - | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)` + = help: within `ManuallyDrop<(dyn Iterator<Item = impl Copy> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)` + = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Copy> + 'static)>` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size | -LL | union U1 { f: &dyn Iterator<Item: Copy> } +LL | union U1 { f: &ManuallyDrop<dyn Iterator<Item: Copy>> } | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | union U1 { f: Box<dyn Iterator<Item: Copy>> } - | ++++ + +LL | union U1 { f: Box<ManuallyDrop<dyn Iterator<Item: Copy>>> } + | ++++ + error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:25:15 + --> $DIR/inside-adt.rs:26:15 | -LL | union U3 { f: dyn Iterator<Item: 'static> } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)` + = help: within `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)` + = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size | -LL | union U3 { f: &dyn Iterator<Item: 'static> } +LL | union U3 { f: &ManuallyDrop<dyn Iterator<Item: 'static>> } | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | union U3 { f: Box<dyn Iterator<Item: 'static>> } - | ++++ + +LL | union U3 { f: Box<ManuallyDrop<dyn Iterator<Item: 'static>>> } + | ++++ + error: aborting due to 13 previous errors diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs index 97c5acf1f72ca..46e5aef04031a 100644 --- a/src/test/ui/associated-type-bounds/union-bounds.rs +++ b/src/test/ui/associated-type-bounds/union-bounds.rs @@ -1,7 +1,6 @@ // run-pass #![feature(associated_type_bounds)] -#![feature(untagged_unions)] #![allow(unused_assignments)] diff --git a/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr b/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr index 19fc2f652c6be..236552baf9287 100644 --- a/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr +++ b/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr @@ -2,10 +2,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:16:24 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn a<C:Vehicle+Box>(_: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` @@ -23,10 +23,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:20:12 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn b<C>(_: C::Color) where C : Vehicle+Box { | ^^^^^^^^ ambiguous associated type `Color` @@ -44,10 +44,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:24:12 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn c<C>(_: C::Color) where C : Vehicle, C : Box { | ^^^^^^^^ ambiguous associated type `Color` @@ -65,10 +65,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:35:20 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn e(&self, _: X::Color) where X : Box; | ^^^^^^^^ ambiguous associated type `Color` @@ -86,10 +86,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:38:20 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn f(&self, _: X::Color) where X : Box { } | ^^^^^^^^ ambiguous associated type `Color` @@ -107,10 +107,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `X` --> $DIR/associated-type-projection-ambig-between-bound-and-where-clause.rs:30:20 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn d(&self, _: X::Color) where X : Box { } | ^^^^^^^^ ambiguous associated type `Color` diff --git a/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr index 66a4899c77fef..e765f93239841 100644 --- a/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr +++ b/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr @@ -10,10 +10,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:19:32 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn dent<C:BoxCar>(c: C, color: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` @@ -31,10 +31,10 @@ error[E0222]: ambiguous associated type `Color` in bounds of `BoxCar` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:37 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) { | ^^^^^^^^^^^ ambiguous associated type `Color` @@ -49,10 +49,10 @@ error[E0191]: the value of the associated types `Color` (from trait `Box`), `Col --> $DIR/associated-type-projection-from-multiple-supertraits.rs:23:30 | LL | type Color; - | ----------- `Vehicle::Color` defined here + | ---------- `Vehicle::Color` defined here ... LL | type Color; - | ----------- `Box::Color` defined here + | ---------- `Box::Color` defined here ... LL | fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) { | ^^^^^^^^^^^^^^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified @@ -63,10 +63,10 @@ error[E0221]: ambiguous associated type `Color` in bounds of `C` --> $DIR/associated-type-projection-from-multiple-supertraits.rs:28:29 | LL | type Color; - | ----------- ambiguous `Color` from `Vehicle` + | ---------- ambiguous `Color` from `Vehicle` ... LL | type Color; - | ----------- ambiguous `Color` from `Box` + | ---------- ambiguous `Color` from `Box` ... LL | fn paint<C:BoxCar>(c: C, d: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` @@ -84,10 +84,10 @@ error[E0191]: the value of the associated types `Color` (from trait `Box`), `Col --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:32 | LL | type Color; - | ----------- `Vehicle::Color` defined here + | ---------- `Vehicle::Color` defined here ... LL | type Color; - | ----------- `Box::Color` defined here + | ---------- `Box::Color` defined here ... LL | fn dent_object_2<COLOR>(c: dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR { | ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified diff --git a/src/test/ui/associated-types/associated-types-coherence-failure.stderr b/src/test/ui/associated-types/associated-types-coherence-failure.stderr index 211613b371492..40c02dca32f0d 100644 --- a/src/test/ui/associated-types/associated-types-coherence-failure.stderr +++ b/src/test/ui/associated-types/associated-types-coherence-failure.stderr @@ -2,19 +2,19 @@ error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `Co --> $DIR/associated-types-coherence-failure.rs:21:1 | LL | impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned { - | ----------------------------------------------------------------------------- first implementation here + | ------------------------------------------------------------ first implementation here ... LL | impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Cow<'_, _>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Cow<'_, _>` error[E0119]: conflicting implementations of trait `IntoCow<'_, _>` for type `&_` --> $DIR/associated-types-coherence-failure.rs:28:1 | LL | impl<'a, B: ?Sized> IntoCow<'a, B> for <B as ToOwned>::Owned where B: ToOwned { - | ----------------------------------------------------------------------------- first implementation here + | ------------------------------------------------------------ first implementation here ... LL | impl<'a, B: ?Sized> IntoCow<'a, B> for &'a B where B: ToOwned { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr index 521907a60445c..bed63a5e6df03 100644 --- a/src/test/ui/associated-types/associated-types-eq-3.stderr +++ b/src/test/ui/associated-types/associated-types-eq-3.stderr @@ -41,7 +41,7 @@ note: expected this to be `Bar` | LL | type A = usize; | ^^^^^ - = note: required for the cast to the object type `dyn Foo<A = Bar>` + = note: required for the cast from `isize` to the object type `dyn Foo<A = Bar>` error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/associated-types-incomplete-object.stderr b/src/test/ui/associated-types/associated-types-incomplete-object.stderr index 24732271c420f..32866c7146805 100644 --- a/src/test/ui/associated-types/associated-types-incomplete-object.stderr +++ b/src/test/ui/associated-types/associated-types-incomplete-object.stderr @@ -2,7 +2,7 @@ error[E0191]: the value of the associated type `B` (from trait `Foo`) must be sp --> $DIR/associated-types-incomplete-object.rs:23:30 | LL | type B; - | ------- `B` defined here + | ------ `B` defined here ... LL | let b = &42isize as &dyn Foo<A=usize>; | ^^^^^^^^^^^^ help: specify the associated type: `Foo<A=usize, B = Type>` @@ -11,7 +11,7 @@ error[E0191]: the value of the associated type `A` (from trait `Foo`) must be sp --> $DIR/associated-types-incomplete-object.rs:26:30 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here ... LL | let c = &42isize as &dyn Foo<B=char>; | ^^^^^^^^^^^ help: specify the associated type: `Foo<B=char, A = Type>` @@ -20,9 +20,9 @@ error[E0191]: the value of the associated types `A` (from trait `Foo`), `B` (fro --> $DIR/associated-types-incomplete-object.rs:29:30 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here LL | type B; - | ------- `B` defined here + | ------ `B` defined here ... LL | let d = &42isize as &dyn Foo; | ^^^ help: specify the associated types: `Foo<A = Type, B = Type>` diff --git a/src/test/ui/associated-types/associated-types-issue-17359.stderr b/src/test/ui/associated-types/associated-types-issue-17359.stderr index 575a072c558bd..9e40d8095862b 100644 --- a/src/test/ui/associated-types/associated-types-issue-17359.stderr +++ b/src/test/ui/associated-types/associated-types-issue-17359.stderr @@ -2,7 +2,7 @@ error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/associated-types-issue-17359.rs:8:1 | LL | type Type; - | ---------- `Type` from trait + | --------- `Type` from trait ... LL | impl Trait for isize {} | ^^^^^^^^^^^^^^^^^^^^ missing `Type` in implementation diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index da79c7ac77f9d..bd3ee2abd2c76 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -1,3 +1,9 @@ +error[E0277]: the trait bound `(T, U): Get` is not satisfied + --> $DIR/associated-types-no-suitable-supertrait.rs:22:40 + | +LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {} + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` + error[E0277]: the trait bound `Self: Get` is not satisfied --> $DIR/associated-types-no-suitable-supertrait.rs:17:40 | @@ -9,12 +15,6 @@ help: consider further restricting `Self` LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {} | +++++++++++++++ -error[E0277]: the trait bound `(T, U): Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:22:40 - | -LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index 9f1abf2a6c4b6..dbd9a44ed9774 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -4,7 +4,7 @@ error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::It LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter(); | ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | - = note: required for the cast to the object type `dyn Iterator<Item = u32, Item = i32>` + = note: required for the cast from `std::vec::IntoIter<u32>` to the object type `dyn Iterator<Item = u32, Item = i32>` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-path-1.stderr b/src/test/ui/associated-types/associated-types-path-1.stderr index 6512d60b2c295..a67f77e37c707 100644 --- a/src/test/ui/associated-types/associated-types-path-1.stderr +++ b/src/test/ui/associated-types/associated-types-path-1.stderr @@ -8,10 +8,10 @@ error[E0221]: ambiguous associated type `A` in bounds of `T` --> $DIR/associated-types-path-1.rs:11:34 | LL | type A; - | ------- ambiguous `A` from `Foo` + | ------ ambiguous `A` from `Foo` ... LL | type A; - | ------- ambiguous `A` from `Bar` + | ------ ambiguous `A` from `Bar` ... LL | pub fn f2<T: Foo + Bar>(a: T, x: T::A) {} | ^^^^ ambiguous associated type `A` diff --git a/src/test/ui/associated-types/defaults-mixed.stderr b/src/test/ui/associated-types/defaults-mixed.stderr index 69ddd5f2326d1..0f4a6968c70dd 100644 --- a/src/test/ui/associated-types/defaults-mixed.stderr +++ b/src/test/ui/associated-types/defaults-mixed.stderr @@ -2,7 +2,7 @@ error[E0046]: not all trait items implemented, missing: `Bar` --> $DIR/defaults-mixed.rs:11:1 | LL | type Bar; - | --------- `Bar` from trait + | -------- `Bar` from trait ... LL | impl Trait for () {} | ^^^^^^^^^^^^^^^^^ missing `Bar` in implementation @@ -11,7 +11,7 @@ error[E0046]: not all trait items implemented, missing: `Bar` --> $DIR/defaults-mixed.rs:14:1 | LL | type Bar; - | --------- `Bar` from trait + | -------- `Bar` from trait ... LL | impl Trait for bool { | ^^^^^^^^^^^^^^^^^^^ missing `Bar` in implementation diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-2.rs index 2eb956c8dbb08..a89f61a81a57c 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-2.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.rs @@ -12,7 +12,7 @@ impl X<'_> for u32 //~ overflow evaluating the requirement `for<'b> u32: X<'b>` where for<'b> <Self as X<'b>>::U: Clone, { - type U = str; //~ overflow evaluating the requirement `for<'b> u32: X<'b>` + type U = str; } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr index fe9b4d630b910..e007f5a163b41 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -1,28 +1,8 @@ error[E0275]: overflow evaluating the requirement `for<'b> u32: X<'b>` --> $DIR/hr-associated-type-bound-2.rs:11:1 | -LL | / impl X<'_> for u32 -LL | | where -LL | | for<'b> <Self as X<'b>>::U: Clone, -LL | | { -LL | | type U = str; -LL | | } - | |_^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`) -note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` - --> $DIR/hr-associated-type-bound-2.rs:11:6 - | LL | impl X<'_> for u32 - | ^^^^^ ^^^ - = note: 128 redundant requirements hidden - = note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` - -error[E0275]: overflow evaluating the requirement `for<'b> u32: X<'b>` - --> $DIR/hr-associated-type-bound-2.rs:15:5 - | -LL | type U = str; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`) note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` @@ -33,6 +13,6 @@ LL | impl X<'_> for u32 = note: 128 redundant requirements hidden = note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr index 5809c407a5f7f..52294f8c94a56 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -15,10 +15,10 @@ LL | for<'b> <T as Z<'b, u16>>::W: Clone, | ^^^^^ required by this bound in `Z` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + --> $DIR/hr-associated-type-bound-param-2.rs:15:14 | -LL | T: Z<'a, u16>, - | ^^^^^^^^^^ the trait `Clone` is not implemented for `str` +LL | type W = str; + | ^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `Z` @@ -31,10 +31,10 @@ LL | for<'b> <T as Z<'b, u16>>::W: Clone, | ^^^^^ required by this bound in `Z` error[E0277]: the trait bound `str: Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-2.rs:15:14 + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | -LL | type W = str; - | ^^^ the trait `Clone` is not implemented for `str` +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `Clone` is not implemented for `str` | = help: the trait `Clone` is implemented for `String` note: required by a bound in `Z` diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.rs b/src/test/ui/associated-types/impl-wf-cycle-1.rs index ba074210a2b5f..365eddaed138e 100644 --- a/src/test/ui/associated-types/impl-wf-cycle-1.rs +++ b/src/test/ui/associated-types/impl-wf-cycle-1.rs @@ -13,16 +13,14 @@ trait Grault { } impl<T: Grault> Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` where Self::A: Baz, Self::B: Fiz, { type A = (); - //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` type B = bool; - //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` } -//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` fn main() { let x: <(_,) as Grault>::A = (); diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.stderr b/src/test/ui/associated-types/impl-wf-cycle-1.stderr index 73167d0831104..939c9bbdb6b86 100644 --- a/src/test/ui/associated-types/impl-wf-cycle-1.stderr +++ b/src/test/ui/associated-types/impl-wf-cycle-1.stderr @@ -1,42 +1,8 @@ error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` --> $DIR/impl-wf-cycle-1.rs:15:1 | -LL | / impl<T: Grault> Grault for (T,) -LL | | where -LL | | Self::A: Baz, -LL | | Self::B: Fiz, -... | -LL | | -LL | | } - | |_^ - | -note: required because of the requirements on the impl of `Grault` for `(T,)` - --> $DIR/impl-wf-cycle-1.rs:15:17 - | LL | impl<T: Grault> Grault for (T,) - | ^^^^^^ ^^^^ - = note: 1 redundant requirement hidden - = note: required because of the requirements on the impl of `Grault` for `(T,)` - -error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` - --> $DIR/impl-wf-cycle-1.rs:20:5 - | -LL | type A = (); - | ^^^^^^^^^^^^ - | -note: required because of the requirements on the impl of `Grault` for `(T,)` - --> $DIR/impl-wf-cycle-1.rs:15:17 - | -LL | impl<T: Grault> Grault for (T,) - | ^^^^^^ ^^^^ - = note: 1 redundant requirement hidden - = note: required because of the requirements on the impl of `Grault` for `(T,)` - -error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` - --> $DIR/impl-wf-cycle-1.rs:22:5 - | -LL | type B = bool; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required because of the requirements on the impl of `Grault` for `(T,)` --> $DIR/impl-wf-cycle-1.rs:15:17 @@ -46,6 +12,6 @@ LL | impl<T: Grault> Grault for (T,) = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` -error: aborting due to 3 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.rs b/src/test/ui/associated-types/impl-wf-cycle-2.rs index 6fccc54f229ae..f2f3072e344c2 100644 --- a/src/test/ui/associated-types/impl-wf-cycle-2.rs +++ b/src/test/ui/associated-types/impl-wf-cycle-2.rs @@ -5,12 +5,11 @@ trait Grault { } impl<T: Grault> Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` where Self::A: Copy, { type A = (); - //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` } -//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` fn main() {} diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.stderr b/src/test/ui/associated-types/impl-wf-cycle-2.stderr index a17e63f28fe91..d02ed2cacdf85 100644 --- a/src/test/ui/associated-types/impl-wf-cycle-2.stderr +++ b/src/test/ui/associated-types/impl-wf-cycle-2.stderr @@ -1,26 +1,8 @@ error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` --> $DIR/impl-wf-cycle-2.rs:7:1 | -LL | / impl<T: Grault> Grault for (T,) -LL | | where -LL | | Self::A: Copy, -LL | | { -LL | | type A = (); -LL | | -LL | | } - | |_^ - | -note: required because of the requirements on the impl of `Grault` for `(T,)` - --> $DIR/impl-wf-cycle-2.rs:7:17 - | LL | impl<T: Grault> Grault for (T,) - | ^^^^^^ ^^^^ - -error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` - --> $DIR/impl-wf-cycle-2.rs:11:5 - | -LL | type A = (); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required because of the requirements on the impl of `Grault` for `(T,)` --> $DIR/impl-wf-cycle-2.rs:7:17 @@ -28,6 +10,6 @@ note: required because of the requirements on the impl of `Grault` for `(T,)` LL | impl<T: Grault> Grault for (T,) | ^^^^^^ ^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr index 71655d54baa2c..700923c1b3f58 100644 --- a/src/test/ui/associated-types/issue-22560.stderr +++ b/src/test/ui/associated-types/issue-22560.stderr @@ -1,26 +1,22 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-22560.rs:9:23 | -LL | / trait Sub<Rhs=Self> { -LL | | type Output; -LL | | } - | |_- type parameter `Rhs` must be specified for this -LL | -LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Sub<Rhs>` +LL | trait Sub<Rhs=Self> { + | ------------------- type parameter `Rhs` must be specified for this +... +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Sub<Rhs>` | = note: because of the default `Self` reference, type parameters must be specified on object types error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-22560.rs:9:17 | -LL | / trait Add<Rhs=Self> { -LL | | type Output; -LL | | } - | |_- type parameter `Rhs` must be specified for this +LL | trait Add<Rhs=Self> { + | ------------------- type parameter `Rhs` must be specified for this ... -LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Add<Rhs>` +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Add<Rhs>` | = note: because of the default `Self` reference, type parameters must be specified on object types @@ -39,10 +35,10 @@ error[E0191]: the value of the associated types `Output` (from trait `Add`), `Ou --> $DIR/issue-22560.rs:9:17 | LL | type Output; - | ------------ `Output` defined here + | ----------- `Output` defined here ... LL | type Output; - | ------------ `Output` defined here + | ----------- `Output` defined here ... LL | type Test = dyn Add + Sub; | ^^^ ^^^ associated type `Output` must be specified diff --git a/src/test/ui/associated-types/issue-23595-1.stderr b/src/test/ui/associated-types/issue-23595-1.stderr index bb455684ee3ef..4307477a56afe 100644 --- a/src/test/ui/associated-types/issue-23595-1.stderr +++ b/src/test/ui/associated-types/issue-23595-1.stderr @@ -2,14 +2,11 @@ error[E0191]: the value of the associated types `ChildKey` (from trait `Hierarch --> $DIR/issue-23595-1.rs:8:58 | LL | type Value; - | ----------- `Value` defined here + | ---------- `Value` defined here LL | type ChildKey; - | -------------- `ChildKey` defined here + | ------------- `ChildKey` defined here LL | type Children = dyn Index<Self::ChildKey, Output=dyn Hierarchy>; - | -----------------------------------------------------^^^^^^^^^-- - | | | - | | help: specify the associated types: `Hierarchy<Value = Type, ChildKey = Type, Children = Type>` - | `Children` defined here + | ------------- `Children` defined here ^^^^^^^^^ help: specify the associated types: `Hierarchy<Value = Type, ChildKey = Type, Children = Type>` error: aborting due to previous error diff --git a/src/test/ui/associated-types/issue-47814.rs b/src/test/ui/associated-types/issue-47814.rs new file mode 100644 index 0000000000000..90e8a3bc2f2f4 --- /dev/null +++ b/src/test/ui/associated-types/issue-47814.rs @@ -0,0 +1,13 @@ +struct ArpIPv4<'a> { + s: &'a u8 +} + +impl<'a> ArpIPv4<'a> { + const LENGTH: usize = 20; + + pub fn to_buffer() -> [u8; Self::LENGTH] { //~ ERROR generic `Self` types are currently not permitted in anonymous constants + unimplemented!() + } +} + +pub fn main() {} diff --git a/src/test/ui/associated-types/issue-47814.stderr b/src/test/ui/associated-types/issue-47814.stderr new file mode 100644 index 0000000000000..2e4ddb81166b4 --- /dev/null +++ b/src/test/ui/associated-types/issue-47814.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/issue-47814.rs:8:32 + | +LL | pub fn to_buffer() -> [u8; Self::LENGTH] { + | ^^^^ + | +note: not a concrete type + --> $DIR/issue-47814.rs:5:10 + | +LL | impl<'a> ArpIPv4<'a> { + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr index 45d2dfb53757b..a84b599b52b68 100644 --- a/src/test/ui/associated-types/issue-59324.stderr +++ b/src/test/ui/associated-types/issue-59324.stderr @@ -5,10 +5,7 @@ LL | / pub trait ThriftService<Bug: NotFoo>: LL | | LL | | LL | | Service<AssocType = <Bug as Foo>::OnlyFoo> -... | -LL | | -LL | | } - | |_^ the trait `Foo` is not implemented for `Bug` + | |______________________________________________^ the trait `Foo` is not implemented for `Bug` | help: consider further restricting this bound | @@ -46,6 +43,12 @@ help: consider further restricting this bound LL | pub trait ThriftService<Bug: NotFoo + Foo>: | +++++ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/issue-59324.rs:23:29 + | +LL | fn with_factory<H>(factory: dyn ThriftService<()>) {} + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` + error[E0277]: the trait bound `Bug: Foo` is not satisfied --> $DIR/issue-59324.rs:19:10 | @@ -57,12 +60,6 @@ help: consider further restricting this bound LL | pub trait ThriftService<Bug: NotFoo + Foo>: | +++++ -error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/issue-59324.rs:23:29 - | -LL | fn with_factory<H>(factory: dyn ThriftService<()>) {} - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-65774-1.stderr b/src/test/ui/associated-types/issue-65774-1.stderr index e468a1b3ba484..419de689c52da 100644 --- a/src/test/ui/associated-types/issue-65774-1.stderr +++ b/src/test/ui/associated-types/issue-65774-1.stderr @@ -23,7 +23,7 @@ note: required because of the requirements on the impl of `MyDisplay` for `&mut | LL | impl<'a, T: MyDisplay> MyDisplay for &'a mut T { } | ^^^^^^^^^ ^^^^^^^^^ - = note: required for the cast to the object type `dyn MyDisplay` + = note: required for the cast from `&mut T` to the object type `dyn MyDisplay` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/issue-65774-2.stderr b/src/test/ui/associated-types/issue-65774-2.stderr index 4cef4db4698a7..c22302cdc2626 100644 --- a/src/test/ui/associated-types/issue-65774-2.stderr +++ b/src/test/ui/associated-types/issue-65774-2.stderr @@ -18,7 +18,7 @@ LL | writer.my_write(valref) | ^^^^^^ the trait `MyDisplay` is not implemented for `T` | = help: the trait `MyDisplay` is implemented for `&'a mut T` - = note: required for the cast to the object type `dyn MyDisplay` + = note: required for the cast from `T` to the object type `dyn MyDisplay` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/issue-85103.stderr b/src/test/ui/associated-types/issue-85103.stderr index 142f3c411ec5c..bddd1dce8e647 100644 --- a/src/test/ui/associated-types/issue-85103.stderr +++ b/src/test/ui/associated-types/issue-85103.stderr @@ -2,7 +2,7 @@ error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, --> $DIR/issue-85103.rs:6:1 | LL | type Edges<'a, E> = Cow<'a, [E]>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr index 8c52736b02c4c..f617df984ae35 100644 --- a/src/test/ui/associated-types/missing-associated-types.stderr +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -13,7 +13,7 @@ error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` ( --> $DIR/missing-associated-types.rs:12:21 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here ... LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>; | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated type `A` must be specified @@ -42,9 +42,9 @@ error[E0191]: the value of the associated types `A` (from trait `Z`), `B` (from --> $DIR/missing-associated-types.rs:15:21 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here LL | type B; - | ------- `B` defined here + | ------ `B` defined here ... LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>; | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified @@ -78,7 +78,7 @@ error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` ( --> $DIR/missing-associated-types.rs:18:21 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here ... LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>; | ^^^^^^^^ ^^^^^^^^ ^^^^^^ associated type `A` must be specified diff --git a/src/test/ui/async-await/async-await-let-else.rs b/src/test/ui/async-await/async-await-let-else.rs new file mode 100644 index 0000000000000..7ea07ae9add1b --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.rs @@ -0,0 +1,53 @@ +// edition:2021 +#![feature(let_else)] +use std::rc::Rc; + +async fn foo(x: Option<bool>) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await + }; +} + +async fn bar() -> ! { + panic!() +} + +fn is_send<T: Send>(_: T) {} + +async fn foo2(x: Option<bool>) { + let Some(_) = x else { + bar2(Rc::new(())).await + }; +} + +async fn bar2<T>(_: T) -> ! { + panic!() +} + +async fn foo3(x: Option<bool>) { + let Some(_) = x else { + (Rc::new(()), bar().await); + return; + }; +} + +async fn foo4(x: Option<bool>) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await; + println!("{:?}", r); + return; + }; +} + +fn main() { + is_send(foo(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo2(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo3(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo4(Some(true))); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr new file mode 100644 index 0000000000000..4d23e27c426b2 --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.stderr @@ -0,0 +1,94 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:45:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:8:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:47:13 + | +LL | is_send(foo2(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:20:26 + | +LL | bar2(Rc::new(())).await + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +LL | }; + | - `Rc::new(())` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:49:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:30:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +note: `Rc::new(())` is later dropped here + --> $DIR/async-await-let-else.rs:30:35 + | +LL | (Rc::new(()), bar().await); + | ^ +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:51:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:38:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +... +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs index 3d22025bf286a..9cabf16f8bba9 100644 --- a/src/test/ui/async-await/async-await.rs +++ b/src/test/ui/async-await/async-await.rs @@ -6,7 +6,7 @@ #![allow(unused)] -// edition:2018 +// edition: 2018 // aux-build:arc_wake.rs extern crate arc_wake; diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index e0818337d2039..e5887689690e7 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -37,7 +37,7 @@ error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Out LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast to the object type `dyn Future<Output = ()>` + = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:12:43 @@ -53,7 +53,7 @@ error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Out LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast to the object type `dyn Future<Output = ()>` + = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:47:44 diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs index 6e1b155e181ee..8bf1385b3c5cd 100644 --- a/src/test/ui/async-await/await-into-future.rs +++ b/src/test/ui/async-await/await-into-future.rs @@ -1,8 +1,6 @@ // run-pass // aux-build: issue-72470-lib.rs // edition:2021 -#![feature(into_future)] - extern crate issue_72470_lib; use std::{future::{Future, IntoFuture}, pin::Pin}; diff --git a/src/test/ui/async-await/default-struct-update.rs b/src/test/ui/async-await/default-struct-update.rs new file mode 100644 index 0000000000000..64fb6280dd7bb --- /dev/null +++ b/src/test/ui/async-await/default-struct-update.rs @@ -0,0 +1,22 @@ +// build-pass +// edition:2018 +// compile-flags: -Zdrop-tracking=y + +fn main() { + let _ = foo(); +} + +async fn from_config(_: Config) {} + +async fn foo() { + from_config(Config { + nickname: None, + ..Default::default() + }) + .await; +} + +#[derive(Default)] +struct Config { + nickname: Option<Box<u8>>, +} diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr index 43b7cb8cece36..2ce7309e1de63 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -1,5 +1,5 @@ error[E0277]: `Sender<i32>` cannot be shared between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 + --> $DIR/issue-70935-complex-spans.rs:12:45 | LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ `Sender<i32>` cannot be shared between threads safely @@ -7,28 +7,23 @@ LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { = help: the trait `Sync` is not implemented for `Sender<i32>` = note: required because of the requirements on the impl of `Send` for `&Sender<i32>` note: required because it's used within this closure - --> $DIR/issue-70935-complex-spans.rs:25:13 + --> $DIR/issue-70935-complex-spans.rs:16:13 | -LL | baz(|| async{ - | _____________^ -LL | | foo(tx.clone()); -LL | | }).await; - | |_________^ +LL | baz(|| async{ + | ^^ note: required because it's used within this `async fn` body --> $DIR/issue-70935-complex-spans.rs:9:67 | LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { | ___________________________________________________________________^ -LL | | LL | | } | |_^ - = note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()` + = note: required because it captures the following types: `ResumeTy`, `impl for<'r, 's, 't0> Future<Output = ()>`, `()` note: required because it's used within this `async` block - --> $DIR/issue-70935-complex-spans.rs:23:16 + --> $DIR/issue-70935-complex-spans.rs:15:16 | LL | async move { | ________________^ -LL | | LL | | baz(|| async{ LL | | foo(tx.clone()); LL | | }).await; diff --git a/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr index 2174f260a7135..2b81b400099f4 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/issue-70935-complex-spans.rs:13:45 + --> $DIR/issue-70935-complex-spans.rs:12:45 | LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `Sync` is not implemented for `Sender<i32>` note: future is not `Send` as this value is used across an await - --> $DIR/issue-70935-complex-spans.rs:27:11 + --> $DIR/issue-70935-complex-spans.rs:18:11 | LL | baz(|| async{ | _____________- @@ -14,9 +14,9 @@ LL | | foo(tx.clone()); LL | | }).await; | | - ^^^^^^ await occurs here, with the value maybe used later | |_________| - | has type `[closure@$DIR/issue-70935-complex-spans.rs:25:13: 27:10]` which is not `Send` + | has type `[closure@$DIR/issue-70935-complex-spans.rs:16:13: 16:15]` which is not `Send` note: the value is later dropped here - --> $DIR/issue-70935-complex-spans.rs:27:17 + --> $DIR/issue-70935-complex-spans.rs:18:17 | LL | }).await; | ^ diff --git a/src/test/ui/async-await/issue-70935-complex-spans.rs b/src/test/ui/async-await/issue-70935-complex-spans.rs index f45ce1f25efa0..48847cdf974bd 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.rs +++ b/src/test/ui/async-await/issue-70935-complex-spans.rs @@ -7,22 +7,13 @@ use std::future::Future; async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { -//[drop_tracking]~^ within this `async fn` body } fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send { - //[normal]~^ ERROR: future cannot be sent between threads safely - //[drop_tracking]~^^ ERROR: `Sender<i32>` cannot be shared - //[drop_tracking]~| NOTE: cannot be shared - //[drop_tracking]~| NOTE: requirements on the impl of `Send` - //[drop_tracking]~| NOTE: captures the following types - //[drop_tracking]~| NOTE: in this expansion - //[drop_tracking]~| NOTE: in this expansion - //[drop_tracking]~| NOTE: in this expansion - //[drop_tracking]~| NOTE: in this expansion + //[normal]~^ ERROR future cannot be sent between threads safely + //[drop_tracking]~^^ ERROR `Sender<i32>` cannot be shared between threads async move { - //[drop_tracking]~^ within this `async` block - baz(|| async{ //[drop_tracking]~ NOTE: used within this closure + baz(|| async{ foo(tx.clone()); }).await; } diff --git a/src/test/ui/async-await/issue-86507.stderr b/src/test/ui/async-await/issue-86507.stderr index 5bbc20359c64a..0e21dba980deb 100644 --- a/src/test/ui/async-await/issue-86507.stderr +++ b/src/test/ui/async-await/issue-86507.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast to the object type `dyn Future<Output = ()> + Send` + = note: required for the cast from `impl Future<Output = ()>` to the object type `dyn Future<Output = ()> + Send` help: consider further restricting this bound | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index ccdd9c57a0f55..5cbbf89a222a7 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -24,15 +24,15 @@ LL | fn main() { LL | (|_| 2333).await; | ^^^^^^ only allowed inside `async` functions and blocks -error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future +error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future --> $DIR/issue-62009-1.rs:12:15 | LL | (|_| 2333).await; - | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future + | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future | - = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` - = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited - = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` + = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` + = note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited + = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` help: remove the `.await` | LL - (|_| 2333).await; diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs index df2ca025705d3..1dbf5db6c32ed 100644 --- a/src/test/ui/async-await/issues/issue-65159.rs +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -6,6 +6,7 @@ async fn copy() -> Result<()> //~^ ERROR this enum takes 2 generic arguments { Ok(()) + //~^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65159.stderr b/src/test/ui/async-await/issues/issue-65159.stderr index 45f5ec40cd758..9918f569cbc89 100644 --- a/src/test/ui/async-await/issues/issue-65159.stderr +++ b/src/test/ui/async-await/issues/issue-65159.stderr @@ -16,6 +16,18 @@ help: add missing generic argument LL | async fn copy() -> Result<(), E> | +++ -error: aborting due to previous error +error[E0282]: type annotations needed + --> $DIR/issue-65159.rs:8:5 + | +LL | Ok(()) + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Ok::<(), E>(()) + | +++++++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0282. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.rs b/src/test/ui/async-await/no-non-guaranteed-initialization.rs index 24070fe33083c..c4d81bf83a3c4 100644 --- a/src/test/ui/async-await/no-non-guaranteed-initialization.rs +++ b/src/test/ui/async-await/no-non-guaranteed-initialization.rs @@ -6,8 +6,7 @@ async fn no_non_guaranteed_initialization(x: usize) -> usize { if x > 5 { y = echo(10).await; } - y - //~^ use of possibly-uninitialized variable: `y` + y //~ ERROR E0381 } async fn echo(x: usize) -> usize { x + 1 } diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr index f5991f4bccac9..12c15bf56ce22 100644 --- a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr +++ b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr @@ -1,8 +1,15 @@ -error[E0381]: use of possibly-uninitialized variable: `y` +error[E0381]: used binding `y` is possibly-uninitialized --> $DIR/no-non-guaranteed-initialization.rs:9:5 | +LL | let y; + | - binding declared here but left uninitialized +LL | if x > 5 { + | ----- if this `if` condition is `false`, `y` is not initialized +LL | y = echo(10).await; +LL | } + | - an `else` arm might be missing here, initializing `y` LL | y - | ^ use of possibly-uninitialized `y` + | ^ `y` used here but it is possibly-uninitialized error: aborting due to previous error diff --git a/src/test/ui/async-await/non-trivial-drop.rs b/src/test/ui/async-await/non-trivial-drop.rs new file mode 100644 index 0000000000000..a3167215dc32b --- /dev/null +++ b/src/test/ui/async-await/non-trivial-drop.rs @@ -0,0 +1,36 @@ +// build-pass +// edition:2018 +// compile-flags: -Zdrop-tracking=y + +#![feature(generators)] + +fn main() { + let _ = foo(); +} + +fn foo() { + || { + yield drop(Config { + nickname: NonCopy, + b: NonCopy2, + }.nickname); + }; +} + +#[derive(Default)] +struct NonCopy; +impl Drop for NonCopy { + fn drop(&mut self) {} +} + +#[derive(Default)] +struct NonCopy2; +impl Drop for NonCopy2 { + fn drop(&mut self) {} +} + +#[derive(Default)] +struct Config { + nickname: NonCopy, + b: NonCopy2, +} diff --git a/src/test/ui/async-await/partial-initialization-across-await.rs b/src/test/ui/async-await/partial-initialization-across-await.rs index 8a98a4b0f6bb4..7577aee3fb7d6 100644 --- a/src/test/ui/async-await/partial-initialization-across-await.rs +++ b/src/test/ui/async-await/partial-initialization-across-await.rs @@ -10,8 +10,7 @@ async fn noop() {} async fn test_tuple() { let mut t: (i32, i32); - t.0 = 42; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 42; //~ ERROR E0381 noop().await; t.1 = 88; let _ = t; @@ -19,8 +18,7 @@ async fn test_tuple() { async fn test_tuple_struct() { let mut t: T; - t.0 = 42; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 42; //~ ERROR E0381 noop().await; t.1 = 88; let _ = t; @@ -28,8 +26,7 @@ async fn test_tuple_struct() { async fn test_struct() { let mut t: S; - t.x = 42; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.x = 42; //~ ERROR E0381 noop().await; t.y = 88; let _ = t; diff --git a/src/test/ui/async-await/partial-initialization-across-await.stderr b/src/test/ui/async-await/partial-initialization-across-await.stderr index 9a510c22c4b1e..6a0eeffb94611 100644 --- a/src/test/ui/async-await/partial-initialization-across-await.stderr +++ b/src/test/ui/async-await/partial-initialization-across-await.stderr @@ -1,20 +1,32 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/partial-initialization-across-await.rs:13:5 | +LL | let mut t: (i32, i32); + | ----- binding declared here but left uninitialized LL | t.0 = 42; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/partial-initialization-across-await.rs:22:5 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-await.rs:21:5 | +LL | let mut t: T; + | ----- binding declared here but left uninitialized LL | t.0 = 42; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/partial-initialization-across-await.rs:31:5 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-await.rs:29:5 | +LL | let mut t: S; + | ----- binding declared here but left uninitialized LL | t.x = 42; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/pin-needed-to-poll.stderr b/src/test/ui/async-await/pin-needed-to-poll.stderr index c47ec5dddb6e2..2e8723b2743a7 100644 --- a/src/test/ui/async-await/pin-needed-to-poll.stderr +++ b/src/test/ui/async-await/pin-needed-to-poll.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `poll` found for struct `Sleep` in the current sco --> $DIR/pin-needed-to-poll.rs:42:20 | LL | struct Sleep; - | ------------- method `poll` not found for this + | ------------ method `poll` not found for this struct ... LL | self.sleep.poll(cx) | ^^^^ method not found in `Sleep` diff --git a/src/test/ui/async-await/type-parameter-send.rs b/src/test/ui/async-await/type-parameter-send.rs new file mode 100644 index 0000000000000..ab2b62aa5aa1c --- /dev/null +++ b/src/test/ui/async-await/type-parameter-send.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: --crate-type lib +// edition:2018 + +fn assert_send<F: Send>(_: F) {} + +async fn __post<T>() -> T { + if false { + todo!() + } else { + async {}.await; + todo!() + } +} + +fn foo<T>() { + assert_send(__post::<T>()); +} diff --git a/src/test/ui/attributes/invalid-doc-attr.stderr b/src/test/ui/attributes/invalid-doc-attr.stderr index 55006b2087eb0..a4fa3817905c7 100644 --- a/src/test/ui/attributes/invalid-doc-attr.stderr +++ b/src/test/ui/attributes/invalid-doc-attr.stderr @@ -12,7 +12,7 @@ LL | #![deny(warnings)] = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] @@ -29,7 +29,7 @@ LL | pub fn foo() {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information error: this attribute can only be applied at the crate level --> $DIR/invalid-doc-attr.rs:15:12 @@ -39,7 +39,7 @@ LL | #![doc(test(no_crate_inject))] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information error: conflicting doc inlining attributes --> $DIR/invalid-doc-attr.rs:28:7 @@ -59,7 +59,7 @@ LL | #[doc(test(no_crate_inject))] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information error: this attribute can only be applied to a `use` item --> $DIR/invalid-doc-attr.rs:22:11 @@ -72,7 +72,7 @@ LL | pub fn baz() {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information error: aborting due to 6 previous errors diff --git a/src/test/ui/attributes/multiple-invalid.stderr b/src/test/ui/attributes/multiple-invalid.stderr index 9bd29f15dbcca..a8dba0ba37d3a 100644 --- a/src/test/ui/attributes/multiple-invalid.stderr +++ b/src/test/ui/attributes/multiple-invalid.stderr @@ -7,14 +7,14 @@ LL | #[inline] LL | const FOO: u8 = 0; | ------------------ not a function or closure -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/multiple-invalid.rs:6:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | const FOO: u8 = 0; - | ------------------ not a function + | ------------------ not a function definition error: aborting due to 2 previous errors diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.stderr b/src/test/ui/auto-traits/suspicious-impls-lint.stderr index 03460b28dcd5a..97b2d7221fdb5 100644 --- a/src/test/ui/auto-traits/suspicious-impls-lint.stderr +++ b/src/test/ui/auto-traits/suspicious-impls-lint.stderr @@ -2,7 +2,7 @@ error: cross-crate traits with a default impl, like `Send`, should not be specia --> $DIR/suspicious-impls-lint.rs:9:1 | LL | unsafe impl<T: Send> Send for MayImplementSendErr<&T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/suspicious-impls-lint.rs:1:9 @@ -16,13 +16,13 @@ note: try using the same sequence of generic parameters as the struct definition --> $DIR/suspicious-impls-lint.rs:8:1 | LL | struct MayImplementSendErr<T>(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cross-crate traits with a default impl, like `Send`, should not be specialized --> $DIR/suspicious-impls-lint.rs:21:1 | LL | unsafe impl Send for ContainsVec<i32> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> @@ -31,13 +31,13 @@ note: try using the same sequence of generic parameters as the struct definition --> $DIR/suspicious-impls-lint.rs:20:1 | LL | struct ContainsVec<T>(Vec<T>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: cross-crate traits with a default impl, like `Send`, should not be specialized --> $DIR/suspicious-impls-lint.rs:32:1 | LL | unsafe impl<T: Send> Send for TwoParamsSame<T, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> @@ -46,13 +46,13 @@ note: try using the same sequence of generic parameters as the struct definition --> $DIR/suspicious-impls-lint.rs:31:1 | LL | struct TwoParamsSame<T, U>(T, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cross-crate traits with a default impl, like `Send`, should not be specialized --> $DIR/suspicious-impls-lint.rs:40:1 | LL | unsafe impl<T> Send for WithPhantomDataSend<*const T, i8> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> @@ -61,13 +61,13 @@ note: try using the same sequence of generic parameters as the struct definition --> $DIR/suspicious-impls-lint.rs:39:1 | LL | pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cross-crate traits with a default impl, like `Sync`, should not be specialized --> $DIR/suspicious-impls-lint.rs:46:1 | LL | unsafe impl<T> Sync for WithLifetime<'static, Vec<T>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> @@ -76,7 +76,7 @@ note: try using the same sequence of generic parameters as the struct definition --> $DIR/suspicious-impls-lint.rs:44:1 | LL | pub struct WithLifetime<'a, T>(&'a (), T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/backtrace-apple-no-dsymutil.rs b/src/test/ui/backtrace-apple-no-dsymutil.rs index 492ff6356bcaf..d32ad11a122df 100644 --- a/src/test/ui/backtrace-apple-no-dsymutil.rs +++ b/src/test/ui/backtrace-apple-no-dsymutil.rs @@ -1,5 +1,6 @@ // run-pass +// compile-flags:-Cstrip=none // compile-flags:-g -Csplit-debuginfo=unpacked // only-macos diff --git a/src/test/ui/backtrace.rs b/src/test/ui/backtrace.rs index c2d9e222b84a4..e2ac43fffc9ef 100644 --- a/src/test/ui/backtrace.rs +++ b/src/test/ui/backtrace.rs @@ -5,6 +5,7 @@ // ignore-sgx no processes // ignore-msvc see #62897 and `backtrace-debuginfo.rs` test // compile-flags:-g +// compile-flags:-Cstrip=none use std::env; use std::process::{Command, Stdio}; @@ -43,6 +44,7 @@ fn expected(fn_name: &str) -> String { format!(" backtrace::{}", fn_name) } +#[cfg(not(panic = "abort"))] fn contains_verbose_expected(s: &str, fn_name: &str) -> bool { // HACK(eddyb) work around the fact that verbosely demangled stack traces // (from `RUST_BACKTRACE=full`, or, as is the case here, panic-in-panic) diff --git a/src/test/ui/binding/issue-53114-safety-checks.rs b/src/test/ui/binding/issue-53114-safety-checks.rs index 5042ad024afff..d0eb28c571411 100644 --- a/src/test/ui/binding/issue-53114-safety-checks.rs +++ b/src/test/ui/binding/issue-53114-safety-checks.rs @@ -3,9 +3,9 @@ // captures the behavior of how `_` bindings are handled with respect to how we // flag expressions that are meant to request unsafe blocks. -#![feature(untagged_unions)] - +#[derive(Copy, Clone)] struct I(i64); +#[derive(Copy, Clone)] struct F(f64); union U { a: I, b: F } diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr index 2cd6d1abfdcdb..695b01d5ee3ad 100644 --- a/src/test/ui/binop/binop-move-semantics.stderr +++ b/src/test/ui/binop/binop-move-semantics.stderr @@ -63,8 +63,20 @@ LL | use_mut(n); use_imm(m); error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/binop-move-semantics.rs:30:5 | -LL | *m - | ^^ move occurs because `*m` has type `T`, which does not implement the `Copy` trait +LL | *m + | -^ + | | + | _____move occurs because `*m` has type `T`, which does not implement the `Copy` trait + | | +LL | | + +LL | | *n; + | |______- `*m` moved due to usage in operator + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/binop-move-semantics.rs:32:5 diff --git a/src/test/ui/binop/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr index 1875ea06a06d5..b9c7e1bea706a 100644 --- a/src/test/ui/binop/issue-28837.stderr +++ b/src/test/ui/binop/issue-28837.stderr @@ -10,18 +10,12 @@ note: an implementation of `Add<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Add<_>` + | ^^^^^^^^ must implement `Add<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Add<Rhs = Self> { -LL | | /// The resulting type after applying the `+` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn add(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Add<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: cannot subtract `A` from `A` --> $DIR/issue-28837.rs:8:7 @@ -35,18 +29,12 @@ note: an implementation of `Sub<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Sub<_>` + | ^^^^^^^^ must implement `Sub<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Sub<Rhs = Self> { -LL | | /// The resulting type after applying the `-` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn sub(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Sub<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: cannot multiply `A` by `A` --> $DIR/issue-28837.rs:10:7 @@ -60,18 +48,12 @@ note: an implementation of `Mul<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Mul<_>` + | ^^^^^^^^ must implement `Mul<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Mul<Rhs = Self> { -LL | | /// The resulting type after applying the `*` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn mul(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Mul<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: cannot divide `A` by `A` --> $DIR/issue-28837.rs:12:7 @@ -85,18 +67,12 @@ note: an implementation of `Div<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Div<_>` + | ^^^^^^^^ must implement `Div<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Div<Rhs = Self> { -LL | | /// The resulting type after applying the `/` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn div(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Div<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: cannot mod `A` by `A` --> $DIR/issue-28837.rs:14:7 @@ -110,18 +86,12 @@ note: an implementation of `Rem<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Rem<_>` + | ^^^^^^^^ must implement `Rem<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Rem<Rhs = Self> { -LL | | /// The resulting type after applying the `%` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn rem(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Rem<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: no implementation for `A & A` --> $DIR/issue-28837.rs:16:7 @@ -135,18 +105,12 @@ note: an implementation of `BitAnd<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `BitAnd<_>` + | ^^^^^^^^ must implement `BitAnd<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait BitAnd<Rhs = Self> { -LL | | /// The resulting type after applying the `&` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn bitand(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait BitAnd<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: no implementation for `A | A` --> $DIR/issue-28837.rs:18:7 @@ -160,18 +124,12 @@ note: an implementation of `BitOr<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `BitOr<_>` + | ^^^^^^^^ must implement `BitOr<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait BitOr<Rhs = Self> { -LL | | /// The resulting type after applying the `|` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn bitor(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait BitOr<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: no implementation for `A << A` --> $DIR/issue-28837.rs:20:7 @@ -185,18 +143,12 @@ note: an implementation of `Shl<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Shl<_>` + | ^^^^^^^^ must implement `Shl<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait Shl<Rhs = Self> { -LL | | /// The resulting type after applying the `<<` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn shl(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Shl<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: no implementation for `A >> A` --> $DIR/issue-28837.rs:22:7 @@ -210,18 +162,12 @@ note: an implementation of `Shr<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `Shr<_>` + | ^^^^^^^^ must implement `Shr<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait Shr<Rhs = Self> { -LL | | /// The resulting type after applying the `>>` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn shr(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Shr<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: binary operation `==` cannot be applied to type `A` --> $DIR/issue-28837.rs:24:7 @@ -235,7 +181,7 @@ note: an implementation of `PartialEq<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^ must implement `PartialEq<_>` help: consider annotating `A` with `#[derive(PartialEq)]` | LL | #[derive(PartialEq)] @@ -253,7 +199,7 @@ note: an implementation of `PartialEq<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^ must implement `PartialEq<_>` help: consider annotating `A` with `#[derive(PartialEq)]` | LL | #[derive(PartialEq)] @@ -271,7 +217,7 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `PartialOrd<_>` + | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | LL | #[derive(PartialEq, PartialOrd)] @@ -289,7 +235,7 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `PartialOrd<_>` + | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | LL | #[derive(PartialEq, PartialOrd)] @@ -307,7 +253,7 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `PartialOrd<_>` + | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | LL | #[derive(PartialEq, PartialOrd)] @@ -325,7 +271,7 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` --> $DIR/issue-28837.rs:1:1 | LL | struct A; - | ^^^^^^^^^ must implement `PartialOrd<_>` + | ^^^^^^^^ must implement `PartialOrd<_>` help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | LL | #[derive(PartialEq, PartialOrd)] diff --git a/src/test/ui/binop/issue-3820.stderr b/src/test/ui/binop/issue-3820.stderr index d5c24e1bb6cdb..f21f890691120 100644 --- a/src/test/ui/binop/issue-3820.stderr +++ b/src/test/ui/binop/issue-3820.stderr @@ -14,14 +14,8 @@ LL | struct Thing { note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Mul<Rhs = Self> { -LL | | /// The resulting type after applying the `*` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn mul(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Mul<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/blind/blind-item-block-middle.stderr b/src/test/ui/blind/blind-item-block-middle.stderr index dd83f6edf62a4..eb64fea943398 100644 --- a/src/test/ui/blind/blind-item-block-middle.stderr +++ b/src/test/ui/blind/blind-item-block-middle.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/blind-item-block-middle.rs:6:9 | LL | mod foo { pub struct bar; } - | --------------- unit struct defined here + | -------------- unit struct defined here ... LL | let bar = 5; | ^^^ - this expression has type `{integer}` diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index e9ca0ad9029e6..37bad64c5bf68 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -7,7 +7,7 @@ LL | |y| x + y | ^^^^^^^^^ expected `()`, found closure | = note: expected unit type `()` - found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14]` + found closure `[closure@$DIR/issue-20862.rs:2:5: 2:8]` error[E0618]: expected function, found `()` --> $DIR/issue-20862.rs:7:13 diff --git a/src/test/ui/bogus-tag.stderr b/src/test/ui/bogus-tag.stderr index cb3199e7c886e..899ff4261ba3b 100644 --- a/src/test/ui/bogus-tag.stderr +++ b/src/test/ui/bogus-tag.stderr @@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `Hsl` found for enum `Color` i --> $DIR/bogus-tag.rs:7:16 | LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), } - | ---------- variant or associated item `Hsl` not found here + | ---------- variant or associated item `Hsl` not found for this enum ... LL | Color::Hsl(h, s, l) => { println!("hsl"); } | ^^^ variant or associated item not found in `Color` diff --git a/src/test/ui/borrowck/assign_mutable_fields.stderr b/src/test/ui/borrowck/assign_mutable_fields.stderr index 40f1aae092dc6..1ed92865da55b 100644 --- a/src/test/ui/borrowck/assign_mutable_fields.stderr +++ b/src/test/ui/borrowck/assign_mutable_fields.stderr @@ -1,14 +1,22 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/assign_mutable_fields.rs:9:5 | +LL | let mut x: (u32, u32); + | ----- binding declared here but left uninitialized LL | x.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/assign_mutable_fields.rs:17:5 | +LL | let mut x: (u32, u32); + | ----- binding declared here but left uninitialized LL | x.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr index 003c40d27736d..6235e0db0da18 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr @@ -1,15 +1,13 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9 | -LL | fn bar() -> impl Fn() -> usize { - | --- ------------------ change this to return `FnMut` instead of `Fn` -LL | let mut x = 0; -LL | / move || { -LL | | x += 1; - | | ^^^^^^ cannot assign -LL | | x -LL | | } - | |_____- in this closure +LL | fn bar() -> impl Fn() -> usize { + | --- ------------------ change this to return `FnMut` instead of `Fn` +LL | let mut x = 0; +LL | move || { + | ------- in this closure +LL | x += 1; + | ^^^^^^ cannot assign error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr index a28cb7431e6a9..093589ed0921f 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -5,8 +5,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... LL | let _f = to_fn(|| x = 42); - | ----- ^^^^^^ cannot assign - | | + | ----- -- ^^^^^^ cannot assign + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure @@ -16,8 +17,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... LL | let _g = to_fn(|| set(&mut y)); - | ----- ^^^^^^ cannot borrow as mutable - | | + | ----- -- ^^^^^^ cannot borrow as mutable + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure @@ -27,8 +29,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... LL | to_fn(|| z = 42); - | ----- ^^^^^^ cannot assign - | | + | ----- -- ^^^^^^ cannot assign + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure @@ -38,8 +41,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... LL | let _f = to_fn(move || x = 42); - | ----- ^^^^^^ cannot assign - | | + | ----- ------- ^^^^^^ cannot assign + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure @@ -49,8 +53,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... LL | let _g = to_fn(move || set(&mut y)); - | ----- ^^^^^^ cannot borrow as mutable - | | + | ----- ------- ^^^^^^ cannot borrow as mutable + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure @@ -60,23 +65,21 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F { | - change this to accept `FnMut` instead of `Fn` ... LL | to_fn(move || z = 42); - | ----- ^^^^^^ cannot assign - | | + | ----- ------- ^^^^^^ cannot assign + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/borrow-immutable-upvar-mutation.rs:53:9 | -LL | fn foo() -> Box<dyn Fn() -> usize> { - | --- ---------------------- change this to return `FnMut` instead of `Fn` -LL | let mut x = 0; -LL | Box::new(move || { - | ______________- -LL | | x += 1; - | | ^^^^^^ cannot assign -LL | | x -LL | | }) - | |_____- in this closure +LL | fn foo() -> Box<dyn Fn() -> usize> { + | --- ---------------------- change this to return `FnMut` instead of `Fn` +LL | let mut x = 0; +LL | Box::new(move || { + | ------- in this closure +LL | x += 1; + | ^^^^^^ cannot assign error: aborting due to 7 previous errors diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr index ea74fb966846f..869375cb2c61b 100644 --- a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr +++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr @@ -29,32 +29,28 @@ LL | f(); error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/borrow-raw-address-of-mutability.rs:29:17 | -LL | fn make_fn<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn make_fn<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | let f = make_fn(|| { - | _____________-------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | let y = &raw mut x; - | | ^^^^^^^^^^ cannot borrow as mutable -LL | | }); - | |_____- in this closure +LL | let f = make_fn(|| { + | ------- -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | let y = &raw mut x; + | ^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/borrow-raw-address-of-mutability.rs:37:17 | -LL | fn make_fn<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn make_fn<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | let f = make_fn(move || { - | _____________-------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | let y = &raw mut x; - | | ^^^^^^^^^^ cannot borrow as mutable -LL | | }); - | |_____- in this closure +LL | let f = make_fn(move || { + | ------- ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | let y = &raw mut x; + | ^^^^^^^^^^ cannot borrow as mutable error: aborting due to 5 previous errors diff --git a/src/test/ui/borrowck/borrowck-and-init.rs b/src/test/ui/borrowck/borrowck-and-init.rs index f11d44e2217ba..eeb4f05d60c96 100644 --- a/src/test/ui/borrowck/borrowck-and-init.rs +++ b/src/test/ui/borrowck/borrowck-and-init.rs @@ -2,5 +2,5 @@ fn main() { let i: isize; println!("{}", false && { i = 5; true }); - println!("{}", i); //~ ERROR borrow of possibly-uninitialized variable: `i` + println!("{}", i); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-and-init.stderr b/src/test/ui/borrowck/borrowck-and-init.stderr index d2c7473c036b8..7f3d27d6091d8 100644 --- a/src/test/ui/borrowck/borrowck-and-init.stderr +++ b/src/test/ui/borrowck/borrowck-and-init.stderr @@ -1,8 +1,13 @@ -error[E0381]: borrow of possibly-uninitialized variable: `i` +error[E0381]: used binding `i` is possibly-uninitialized --> $DIR/borrowck-and-init.rs:5:20 | +LL | let i: isize; + | - binding declared here but left uninitialized +LL | +LL | println!("{}", false && { i = 5; true }); + | ----- binding initialized here in some conditions LL | println!("{}", i); - | ^ use of possibly-uninitialized `i` + | ^ `i` used here but it is possibly-uninitialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/borrowck/borrowck-block-unint.rs b/src/test/ui/borrowck/borrowck-block-unint.rs index 1e7306acaee98..8d13b25a35756 100644 --- a/src/test/ui/borrowck/borrowck-block-unint.rs +++ b/src/test/ui/borrowck/borrowck-block-unint.rs @@ -1,7 +1,7 @@ fn force<F>(f: F) where F: FnOnce() { f(); } fn main() { let x: isize; - force(|| { //~ ERROR borrow of possibly-uninitialized variable: `x` + force(|| { //~ ERROR E0381 println!("{}", x); }); } diff --git a/src/test/ui/borrowck/borrowck-block-unint.stderr b/src/test/ui/borrowck/borrowck-block-unint.stderr index 578f89df46ce1..e720db1c6961b 100644 --- a/src/test/ui/borrowck/borrowck-block-unint.stderr +++ b/src/test/ui/borrowck/borrowck-block-unint.stderr @@ -1,8 +1,10 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-block-unint.rs:4:11 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | force(|| { - | ^^ use of possibly-uninitialized `x` + | ^^ `x` used here but it isn't initialized LL | println!("{}", x); | - borrow occurs due to use in closure diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr index 0866f54b9fab6..c99c0f77982ed 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to `**t1`, which is behind a `&` reference --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5 | LL | let t1 = t0; - | -- help: consider changing this to be a mutable reference: `&mut &mut isize` + | -- consider changing this binding's type to be: `&mut &mut isize` LL | let p: &isize = &**t0; LL | **t1 = 22; | ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed new file mode 100644 index 0000000000000..8bf6a2f6db396 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +use std::collections::HashMap; + +fn main() { + let tmp: Box<_>; + let mut buggy_map: HashMap<usize, &usize> = HashMap::new(); + let binding = Box::new(1); + buggy_map.insert(42, &*binding); //~ ERROR temporary value dropped while borrowed + + // but it is ok if we use a temporary + tmp = Box::new(2); + buggy_map.insert(43, &*tmp); +} diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs index 1d05845fc6b20..85481336a305f 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -1,8 +1,6 @@ -use std::collections::HashMap; - - - +// run-rustfix +use std::collections::HashMap; fn main() { let tmp: Box<_>; diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr index 01379ed851200..dea8ac90bec2e 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-borrowed-uniq-rvalue.rs:10:28 + --> $DIR/borrowck-borrowed-uniq-rvalue.rs:8:28 | LL | buggy_map.insert(42, &*Box::new(1)); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -9,7 +9,11 @@ LL | buggy_map.insert(42, &*Box::new(1)); LL | buggy_map.insert(43, &*tmp); | --------------------------- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Box::new(1); +LL ~ buggy_map.insert(42, &*binding); + | error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.rs b/src/test/ui/borrowck/borrowck-break-uninit-2.rs index 126d991a51c6e..3abca33a84add 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.rs +++ b/src/test/ui/borrowck/borrowck-break-uninit-2.rs @@ -6,7 +6,7 @@ fn foo() -> isize { x = 0; } - println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x` + println!("{}", x); //~ ERROR E0381 return 17; } diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr index b134f5cc2d8e3..23ea1a2de7fc7 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr +++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr @@ -1,8 +1,11 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-break-uninit-2.rs:9:20 | +LL | let x: isize; + | - binding declared here but left uninitialized +... LL | println!("{}", x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/borrowck/borrowck-break-uninit.rs b/src/test/ui/borrowck/borrowck-break-uninit.rs index 8ccb21ae8eebf..824f91dbc62c2 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit.rs +++ b/src/test/ui/borrowck/borrowck-break-uninit.rs @@ -6,7 +6,7 @@ fn foo() -> isize { x = 0; } - println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x` + println!("{}", x); //~ ERROR E0381 return 17; } diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr index 652d7d3076fbd..2b9b0a190f6c8 100644 --- a/src/test/ui/borrowck/borrowck-break-uninit.stderr +++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr @@ -1,8 +1,11 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-break-uninit.rs:9:20 | +LL | let x: isize; + | - binding declared here but left uninitialized +... LL | println!("{}", x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.rs b/src/test/ui/borrowck/borrowck-field-sensitivity.rs index 50edfb6ba2db1..03edf445ee97b 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.rs +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.rs @@ -78,20 +78,20 @@ fn fu_move_after_fu_move() { fn copy_after_field_assign_after_uninit() { let mut x: A; - x.a = 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` + x.a = 1; //~ ERROR E0381 drop(x.a); } fn borrow_after_field_assign_after_uninit() { let mut x: A; - x.a = 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` + x.a = 1; //~ ERROR E0381 let p = &x.a; drop(*p); } fn move_after_field_assign_after_uninit() { let mut x: A; - x.b = Box::new(1); //~ ERROR assign to part of possibly-uninitialized variable: `x` + x.b = Box::new(1); //~ ERROR E0381 drop(x.b); } diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr index bb4d2f06016b9..e009f5913edd0 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr @@ -108,23 +108,35 @@ LL | let _z = A { a: 4, .. x }; | = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/borrowck-field-sensitivity.rs:81:5 | +LL | let mut x: A; + | ----- binding declared here but left uninitialized LL | x.a = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/borrowck-field-sensitivity.rs:87:5 | +LL | let mut x: A; + | ----- binding declared here but left uninitialized LL | x.a = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/borrowck-field-sensitivity.rs:94:5 | +LL | let mut x: A; + | ----- binding declared here but left uninitialized LL | x.b = Box::new(1); - | ^^^ use of possibly-uninitialized `x` + | ^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs new file mode 100644 index 0000000000000..f619c045b250f --- /dev/null +++ b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs @@ -0,0 +1,7 @@ +fn f() -> isize { + let mut x: isize; + for _ in 0..0 { x = 10; } + return x; //~ ERROR E0381 +} + +fn main() { f(); } diff --git a/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr new file mode 100644 index 0000000000000..c08c93f361726 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr @@ -0,0 +1,13 @@ +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/borrowck-for-loop-uninitialized-binding.rs:4:12 + | +LL | let mut x: isize; + | ----- binding declared here but left uninitialized +LL | for _ in 0..0 { x = 10; } + | ---- if the `for` loop runs 0 times, `x` is not initialized +LL | return x; + | ^ `x` used here but it is possibly-uninitialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/borrowck-if-no-else.rs b/src/test/ui/borrowck/borrowck-if-no-else.rs index f59bcad6f61d7..534d771be1dfa 100644 --- a/src/test/ui/borrowck/borrowck-if-no-else.rs +++ b/src/test/ui/borrowck/borrowck-if-no-else.rs @@ -2,5 +2,5 @@ fn foo(x: isize) { println!("{}", x); } fn main() { let x: isize; if 1 > 2 { x = 10; } - foo(x); //~ ERROR use of possibly-uninitialized variable: `x` + foo(x); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-if-no-else.stderr b/src/test/ui/borrowck/borrowck-if-no-else.stderr index 3e9d3d4f6d513..9eafc2c2a86e6 100644 --- a/src/test/ui/borrowck/borrowck-if-no-else.stderr +++ b/src/test/ui/borrowck/borrowck-if-no-else.stderr @@ -1,8 +1,13 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` is possibly-uninitialized --> $DIR/borrowck-if-no-else.rs:5:9 | +LL | let x: isize; if 1 > 2 { x = 10; } + | - ----- - an `else` arm might be missing here, initializing `x` + | | | + | | if this `if` condition is `false`, `x` is not initialized + | binding declared here but left uninitialized LL | foo(x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it is possibly-uninitialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-if-with-else.rs b/src/test/ui/borrowck/borrowck-if-with-else.rs index c13318b16c2fa..69d450c59891a 100644 --- a/src/test/ui/borrowck/borrowck-if-with-else.rs +++ b/src/test/ui/borrowck/borrowck-if-with-else.rs @@ -7,5 +7,5 @@ fn main() { } else { x = 10; } - foo(x); //~ ERROR use of possibly-uninitialized variable: `x` + foo(x); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-if-with-else.stderr b/src/test/ui/borrowck/borrowck-if-with-else.stderr index 53b8a6bba2c76..3f0fe291ca250 100644 --- a/src/test/ui/borrowck/borrowck-if-with-else.stderr +++ b/src/test/ui/borrowck/borrowck-if-with-else.stderr @@ -1,8 +1,13 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` is possibly-uninitialized --> $DIR/borrowck-if-with-else.rs:10:9 | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | if 1 > 2 { + | ----- if this condition is `true`, `x` is not initialized +... LL | foo(x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it is possibly-uninitialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr index 30e74c5ec950c..2033e4a573014 100644 --- a/src/test/ui/borrowck/borrowck-in-static.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.stderr @@ -4,9 +4,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | Box::new(|| x) - | ---^ - | | | - | | move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | | captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs index 9905e420f948d..e6476b9c1bef7 100644 --- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs +++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs @@ -1,7 +1,7 @@ fn main() { let j = || -> isize { let i: isize; - i //~ ERROR use of possibly-uninitialized variable: `i` + i //~ ERROR E0381 }; j(); } diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr index 2d1d9bc8fa41d..e8a2fbc91ea64 100644 --- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `i` +error[E0381]: used binding `i` isn't initialized --> $DIR/borrowck-init-in-called-fn-expr.rs:4:9 | +LL | let i: isize; + | - binding declared here but left uninitialized LL | i - | ^ use of possibly-uninitialized `i` + | ^ `i` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs b/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs index 7dd3396c8c2cb..7eb204a0d1672 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs +++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs @@ -1,7 +1,7 @@ fn main() { let f = || -> isize { let i: isize; - i //~ ERROR use of possibly-uninitialized variable: `i` + i //~ ERROR E0381 }; println!("{}", f()); } diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr index fd8b90eda6032..1e950d6a20def 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `i` +error[E0381]: used binding `i` isn't initialized --> $DIR/borrowck-init-in-fn-expr.rs:4:9 | +LL | let i: isize; + | - binding declared here but left uninitialized LL | i - | ^ use of possibly-uninitialized `i` + | ^ `i` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.rs b/src/test/ui/borrowck/borrowck-init-in-fru.rs index d7ec2ed75c85c..c07957ab13973 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fru.rs +++ b/src/test/ui/borrowck/borrowck-init-in-fru.rs @@ -7,6 +7,6 @@ struct Point { fn main() { let mut origin: Point; origin = Point { x: 10, ..origin }; - //~^ ERROR use of possibly-uninitialized variable: `origin` [E0381] + //~^ ERROR E0381 origin.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.stderr index f01afe1466aef..83a3e3e0e3ae0 100644 --- a/src/test/ui/borrowck/borrowck-init-in-fru.stderr +++ b/src/test/ui/borrowck/borrowck-init-in-fru.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `origin` +error[E0381]: used binding `origin` isn't initialized --> $DIR/borrowck-init-in-fru.rs:9:14 | +LL | let mut origin: Point; + | ---------- binding declared here but left uninitialized LL | origin = Point { x: 10, ..origin }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `origin.y` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `origin.y` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.rs b/src/test/ui/borrowck/borrowck-init-op-equal.rs index 784eb8cf85b8a..3d08c1b81a79b 100644 --- a/src/test/ui/borrowck/borrowck-init-op-equal.rs +++ b/src/test/ui/borrowck/borrowck-init-op-equal.rs @@ -1,6 +1,6 @@ fn test() { let v: isize; - v += 1; //~ ERROR use of possibly-uninitialized variable: `v` + v += 1; //~ ERROR E0381 v.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.stderr b/src/test/ui/borrowck/borrowck-init-op-equal.stderr index 6c88778ae0e5a..74704b2abfee8 100644 --- a/src/test/ui/borrowck/borrowck-init-op-equal.stderr +++ b/src/test/ui/borrowck/borrowck-init-op-equal.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `v` +error[E0381]: used binding `v` isn't initialized --> $DIR/borrowck-init-op-equal.rs:3:5 | +LL | let v: isize; + | - binding declared here but left uninitialized LL | v += 1; - | ^^^^^^ use of possibly-uninitialized `v` + | ^^^^^^ `v` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.rs b/src/test/ui/borrowck/borrowck-init-plus-equal.rs index d9d20a2a9c148..2a52a3f4e5eb1 100644 --- a/src/test/ui/borrowck/borrowck-init-plus-equal.rs +++ b/src/test/ui/borrowck/borrowck-init-plus-equal.rs @@ -1,6 +1,6 @@ fn test() { let mut v: isize; - v = v + 1; //~ ERROR use of possibly-uninitialized variable: `v` + v = v + 1; //~ ERROR E0381 v.clone(); } diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr index fe09c8581df0e..7542576d636be 100644 --- a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr +++ b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `v` +error[E0381]: used binding `v` isn't initialized --> $DIR/borrowck-init-plus-equal.rs:3:9 | +LL | let mut v: isize; + | ----- binding declared here but left uninitialized LL | v = v + 1; - | ^ use of possibly-uninitialized `v` + | ^ `v` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index f81b34a641bf0..8ddc48b2a99cd 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -1,18 +1,16 @@ error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure --> $DIR/borrowck-move-by-capture.rs:9:29 | -LL | let bar: Box<_> = Box::new(3); - | --- captured outer variable -LL | let _g = to_fn_mut(|| { - | ________________________- -LL | | let _h = to_fn_once(move || -> isize { *bar }); - | | ^^^^^^^^^^^^^^^^ ---- - | | | | - | | | variable moved due to use in closure - | | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait - | | move out of `bar` occurs here -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let bar: Box<_> = Box::new(3); + | --- captured outer variable +LL | let _g = to_fn_mut(|| { + | -- captured by this `FnMut` closure +LL | let _h = to_fn_once(move || -> isize { *bar }); + | ^^^^^^^^^^^^^^^^ ---- + | | | + | | variable moved due to use in closure + | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait + | move out of `bar` occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-or-init.rs b/src/test/ui/borrowck/borrowck-or-init.rs index 81b0b80bf11b5..079cf899e6dbf 100644 --- a/src/test/ui/borrowck/borrowck-or-init.rs +++ b/src/test/ui/borrowck/borrowck-or-init.rs @@ -2,5 +2,5 @@ fn main() { let i: isize; println!("{}", false || { i = 5; true }); - println!("{}", i); //~ ERROR borrow of possibly-uninitialized variable: `i` + println!("{}", i); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-or-init.stderr b/src/test/ui/borrowck/borrowck-or-init.stderr index 6c757759f7134..0bc24f1b6932f 100644 --- a/src/test/ui/borrowck/borrowck-or-init.stderr +++ b/src/test/ui/borrowck/borrowck-or-init.stderr @@ -1,8 +1,13 @@ -error[E0381]: borrow of possibly-uninitialized variable: `i` +error[E0381]: used binding `i` is possibly-uninitialized --> $DIR/borrowck-or-init.rs:5:20 | +LL | let i: isize; + | - binding declared here but left uninitialized +LL | +LL | println!("{}", false || { i = 5; true }); + | ----- binding initialized here in some conditions LL | println!("{}", i); - | ^ use of possibly-uninitialized `i` + | ^ `i` used here but it is possibly-uninitialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs index 5e5a8cdf4232b..a43a1936678ff 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs +++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs @@ -14,8 +14,7 @@ impl Drop for Test2 { fn stuff() { let mut x : (Test2, Test2); - (x.0).0 = Some(Test); - //~^ ERROR assign of possibly-uninitialized variable: `x.0` + (x.0).0 = Some(Test); //~ ERROR E0381 } fn main() { diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr index 218c4f2de5bc7..d12a482cb69a9 100644 --- a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr +++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr @@ -1,8 +1,12 @@ -error[E0381]: assign of possibly-uninitialized variable: `x.0` +error[E0381]: assigned binding `x.0` isn't fully initialized --> $DIR/borrowck-partial-reinit-4.rs:17:5 | +LL | let mut x : (Test2, Test2); + | ----- binding declared here but left uninitialized LL | (x.0).0 = Some(Test); - | ^^^^^^^ use of possibly-uninitialized `x.0` + | ^^^^^^^ `x.0` assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-return.rs b/src/test/ui/borrowck/borrowck-return.rs index 8c623356f6c6b..a63ffcff732ee 100644 --- a/src/test/ui/borrowck/borrowck-return.rs +++ b/src/test/ui/borrowck/borrowck-return.rs @@ -1,6 +1,6 @@ fn f() -> isize { let x: isize; - return x; //~ ERROR use of possibly-uninitialized variable: `x` + return x; //~ ERROR E0381 } fn main() { f(); } diff --git a/src/test/ui/borrowck/borrowck-return.stderr b/src/test/ui/borrowck/borrowck-return.stderr index bc74e8e343848..1c916e223175c 100644 --- a/src/test/ui/borrowck/borrowck-return.stderr +++ b/src/test/ui/borrowck/borrowck-return.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-return.rs:3:12 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | return x; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr index 8e4932142f0db..2cea4392d6adb 100644 --- a/src/test/ui/borrowck/borrowck-storage-dead.stderr +++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-storage-dead.rs:16:17 | +LL | let x: i32; + | - binding declared here but left uninitialized LL | let _ = x + 1; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.rs b/src/test/ui/borrowck/borrowck-uninit-after-item.rs index e9a389657c8fd..e97ce6aa407ed 100644 --- a/src/test/ui/borrowck/borrowck-uninit-after-item.rs +++ b/src/test/ui/borrowck/borrowck-uninit-after-item.rs @@ -1,5 +1,5 @@ fn main() { let bar; fn baz(_x: isize) { } - baz(bar); //~ ERROR use of possibly-uninitialized variable: `bar` + baz(bar); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr index f7f069b81be02..588b1b0c9729c 100644 --- a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr @@ -1,8 +1,11 @@ -error[E0381]: use of possibly-uninitialized variable: `bar` +error[E0381]: used binding `bar` isn't initialized --> $DIR/borrowck-uninit-after-item.rs:4:9 | +LL | let bar; + | --- binding declared here but left uninitialized +LL | fn baz(_x: isize) { } LL | baz(bar); - | ^^^ use of possibly-uninitialized `bar` + | ^^^ `bar` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr index 7951a5b1b5d70..6a38a79891970 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `a` +error[E0381]: used binding `a` isn't initialized --> $DIR/borrowck-uninit-field-access.rs:21:13 | +LL | let mut a: Point; + | ----- binding declared here but left uninitialized LL | let _ = a.x + 1; - | ^^^ use of possibly-uninitialized `a.x` + | ^^^ `a.x` used here but it isn't initialized error[E0382]: use of moved value: `line1.origin` --> $DIR/borrowck-uninit-field-access.rs:25:13 diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs b/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs index 20350d61d5bb6..92c3692bd2f69 100644 --- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs +++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs @@ -3,32 +3,32 @@ pub fn main() { let x: isize; - x += 1; //~ ERROR use of possibly-uninitialized variable: `x` + x += 1; //~ ERROR E0381 let x: isize; - x -= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x -= 1; //~ ERROR E0381 let x: isize; - x *= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x *= 1; //~ ERROR E0381 let x: isize; - x /= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x /= 1; //~ ERROR E0381 let x: isize; - x %= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x %= 1; //~ ERROR E0381 let x: isize; - x ^= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x ^= 1; //~ ERROR E0381 let x: isize; - x &= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x &= 1; //~ ERROR E0381 let x: isize; - x |= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x |= 1; //~ ERROR E0381 let x: isize; - x <<= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x <<= 1; //~ ERROR E0381 let x: isize; - x >>= 1; //~ ERROR use of possibly-uninitialized variable: `x` + x >>= 1; //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr index f2036df3ce92a..744cb14e662b3 100644 --- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr @@ -1,62 +1,82 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:6:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x += 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:9:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x -= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:12:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x *= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:15:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x /= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:18:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x %= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:21:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x ^= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:24:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x &= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:27:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x |= 1; - | ^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:30:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x <<= 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-in-assignop.rs:33:5 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | x >>= 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` used here but it isn't initialized error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs index 0ccea49f329bb..c36b9707d2287 100644 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs +++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs @@ -5,29 +5,29 @@ struct S<X, Y> { fn main() { let x: &&Box<i32>; - let _y = &**x; //~ [E0381] + let _y = &**x; //~ ERROR [E0381] let x: &&S<i32, i32>; - let _y = &**x; //~ [E0381] + let _y = &**x; //~ ERROR [E0381] let x: &&i32; - let _y = &**x; //~ [E0381] + let _y = &**x; //~ ERROR [E0381] let mut a: S<i32, i32>; - a.x = 0; //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381] + a.x = 0; //~ ERROR [E0381] let _b = &a.x; let mut a: S<&&i32, &&i32>; - a.x = &&0; //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381] + a.x = &&0; //~ ERROR [E0381] let _b = &**a.x; let mut a: S<i32, i32>; - a.x = 0; //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381] + a.x = 0; //~ ERROR [E0381] let _b = &a.y; let mut a: S<&&i32, &&i32>; - a.x = &&0; //~ assign to part of possibly-uninitialized variable: `a` [E0381] + a.x = &&0; //~ ERROR [E0381] let _b = &**a.y; } diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr index d99a50df75b8c..c486cb6dd0cd3 100644 --- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr @@ -1,44 +1,66 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-ref-chain.rs:8:14 | +LL | let x: &&Box<i32>; + | - binding declared here but left uninitialized LL | let _y = &**x; - | ^^^^ use of possibly-uninitialized `**x` + | ^^^^ `**x` used here but it isn't initialized -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-ref-chain.rs:11:14 | +LL | let x: &&S<i32, i32>; + | - binding declared here but left uninitialized LL | let _y = &**x; - | ^^^^ use of possibly-uninitialized `**x` + | ^^^^ `**x` used here but it isn't initialized -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit-ref-chain.rs:14:14 | +LL | let x: &&i32; + | - binding declared here but left uninitialized LL | let _y = &**x; - | ^^^^ use of possibly-uninitialized `**x` + | ^^^^ `**x` used here but it isn't initialized -error[E0381]: assign to part of possibly-uninitialized variable: `a` +error[E0381]: partially assigned binding `a` isn't fully initialized --> $DIR/borrowck-uninit-ref-chain.rs:18:5 | +LL | let mut a: S<i32, i32>; + | ----- binding declared here but left uninitialized LL | a.x = 0; - | ^^^^^^^ use of possibly-uninitialized `a` + | ^^^^^^^ `a` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `a` +error[E0381]: partially assigned binding `a` isn't fully initialized --> $DIR/borrowck-uninit-ref-chain.rs:22:5 | +LL | let mut a: S<&&i32, &&i32>; + | ----- binding declared here but left uninitialized LL | a.x = &&0; - | ^^^^^^^^^ use of possibly-uninitialized `a` + | ^^^^^^^^^ `a` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `a` +error[E0381]: partially assigned binding `a` isn't fully initialized --> $DIR/borrowck-uninit-ref-chain.rs:27:5 | +LL | let mut a: S<i32, i32>; + | ----- binding declared here but left uninitialized LL | a.x = 0; - | ^^^^^^^ use of possibly-uninitialized `a` + | ^^^^^^^ `a` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `a` +error[E0381]: partially assigned binding `a` isn't fully initialized --> $DIR/borrowck-uninit-ref-chain.rs:31:5 | +LL | let mut a: S<&&i32, &&i32>; + | ----- binding declared here but left uninitialized LL | a.x = &&0; - | ^^^^^^^^^ use of possibly-uninitialized `a` + | ^^^^^^^^^ `a` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 7 previous errors diff --git a/src/test/ui/borrowck/borrowck-uninit.rs b/src/test/ui/borrowck/borrowck-uninit.rs index 017b955a39535..5d0ebabb00872 100644 --- a/src/test/ui/borrowck/borrowck-uninit.rs +++ b/src/test/ui/borrowck/borrowck-uninit.rs @@ -2,5 +2,5 @@ fn foo(x: isize) { println!("{}", x); } fn main() { let x: isize; - foo(x); //~ ERROR use of possibly-uninitialized variable: `x` + foo(x); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-uninit.stderr b/src/test/ui/borrowck/borrowck-uninit.stderr index effc209e81659..d5566691a8200 100644 --- a/src/test/ui/borrowck/borrowck-uninit.stderr +++ b/src/test/ui/borrowck/borrowck-uninit.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-uninit.rs:5:9 | +LL | let x: isize; + | - binding declared here but left uninitialized LL | foo(x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.rs b/src/test/ui/borrowck/borrowck-union-move-assign.rs index a24f42d2ddf87..4c96ccdb25aaa 100644 --- a/src/test/ui/borrowck/borrowck-union-move-assign.rs +++ b/src/test/ui/borrowck/borrowck-union-move-assign.rs @@ -1,31 +1,31 @@ -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; // Non-copy struct A; struct B; union U { - a: A, - b: B, + a: ManuallyDrop<A>, + b: ManuallyDrop<B>, } fn main() { unsafe { { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; let a = u.a; //~ ERROR use of moved value: `u` } { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.a = A; + u.a = ManuallyDrop::new(A); let a = u.a; // OK } { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.b = B; + u.b = ManuallyDrop::new(B); let a = u.a; // OK } } diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.stderr b/src/test/ui/borrowck/borrowck-union-move-assign.stderr index 0b1714fd75dc0..af6f6fac40870 100644 --- a/src/test/ui/borrowck/borrowck-union-move-assign.stderr +++ b/src/test/ui/borrowck/borrowck-union-move-assign.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move-assign.rs:17:21 | -LL | let mut u = U { a: A }; +LL | let mut u = U { a: ManuallyDrop::new(A) }; | ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.a; | --- value moved here diff --git a/src/test/ui/borrowck/borrowck-union-move.rs b/src/test/ui/borrowck/borrowck-union-move.rs index d0aa6dff74410..510547ad5bb74 100644 --- a/src/test/ui/borrowck/borrowck-union-move.rs +++ b/src/test/ui/borrowck/borrowck-union-move.rs @@ -1,12 +1,12 @@ -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; #[derive(Clone, Copy)] struct Copy; struct NonCopy; union Unn { - n1: NonCopy, - n2: NonCopy, + n1: ManuallyDrop<NonCopy>, + n2: ManuallyDrop<NonCopy>, } union Ucc { c1: Copy, @@ -14,24 +14,24 @@ union Ucc { } union Ucn { c: Copy, - n: NonCopy, + n: ManuallyDrop<NonCopy>, } fn main() { unsafe { // 2 NonCopy { - let mut u = Unn { n1: NonCopy }; + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; let a = u.n1; let a = u.n1; //~ ERROR use of moved value: `u` } { - let mut u = Unn { n1: NonCopy }; + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; let a = u.n1; let a = u; //~ ERROR use of moved value: `u` } { - let mut u = Unn { n1: NonCopy }; + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; let a = u.n1; let a = u.n2; //~ ERROR use of moved value: `u` } diff --git a/src/test/ui/borrowck/borrowck-union-move.stderr b/src/test/ui/borrowck/borrowck-union-move.stderr index abbb0142a9c30..731607fbdd1f7 100644 --- a/src/test/ui/borrowck/borrowck-union-move.stderr +++ b/src/test/ui/borrowck/borrowck-union-move.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:26:21 | -LL | let mut u = Unn { n1: NonCopy }; +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; | ---- value moved here @@ -11,7 +11,7 @@ LL | let a = u.n1; error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:31:21 | -LL | let mut u = Unn { n1: NonCopy }; +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; | ---- value moved here @@ -21,7 +21,7 @@ LL | let a = u; error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:36:21 | -LL | let mut u = Unn { n1: NonCopy }; +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; | ---- value moved here diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.rs b/src/test/ui/borrowck/borrowck-union-uninitialized.rs index 3cc71e7cece0e..bbe9f22aac307 100644 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.rs +++ b/src/test/ui/borrowck/borrowck-union-uninitialized.rs @@ -10,8 +10,8 @@ fn main() { unsafe { let mut s: S; let mut u: U; - s.a = 0; //~ ERROR assign to part of possibly-uninitialized variable: `s` - u.a = 0; //~ ERROR assign to part of possibly-uninitialized variable: `u` + s.a = 0; //~ ERROR E0381 + u.a = 0; //~ ERROR E0381 let sa = s.a; let ua = u.a; } diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr index bd9ec5e579ca9..b7ff5f3955ee5 100644 --- a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr +++ b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr @@ -1,14 +1,24 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `s` +error[E0381]: partially assigned binding `s` isn't fully initialized --> $DIR/borrowck-union-uninitialized.rs:13:9 | +LL | let mut s: S; + | ----- binding declared here but left uninitialized +LL | let mut u: U; LL | s.a = 0; - | ^^^^^^^ use of possibly-uninitialized `s` + | ^^^^^^^ `s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `u` +error[E0381]: partially assigned binding `u` isn't fully initialized --> $DIR/borrowck-union-uninitialized.rs:14:9 | +LL | let mut u: U; + | ----- binding declared here but left uninitialized +LL | s.a = 0; LL | u.a = 0; - | ^^^^^^^ use of possibly-uninitialized `u` + | ^^^^^^^ `u` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr index d1b396aba8257..459cf1398b750 100644 --- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr @@ -1,14 +1,18 @@ -error[E0381]: use of possibly-uninitialized variable: `w` +error[E0381]: used binding `w` isn't initialized --> $DIR/borrowck-use-in-index-lvalue.rs:3:5 | +LL | let w: &mut [isize]; + | - binding declared here but left uninitialized LL | w[5] = 0; - | ^^^^ use of possibly-uninitialized `*w` + | ^^^^ `*w` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `w` +error[E0381]: used binding `w` isn't initialized --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 | +LL | let mut w: &mut [isize]; + | ----- binding declared here but left uninitialized LL | w[5] = 0; - | ^^^^ use of possibly-uninitialized `*w` + | ^^^^ `*w` used here but it isn't initialized error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr index ca5227c98c862..942ed4fc6cabf 100644 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr @@ -1,8 +1,10 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13 | +LL | let x: &i32; + | - binding declared here but left uninitialized LL | let y = x as *const dyn Foo; - | ^ use of possibly-uninitialized `*x` + | ^ `*x` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr index 24897a0f2dc9c..f3289e239818a 100644 --- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr +++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr @@ -1,8 +1,10 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13 | +LL | let x: &i32; + | - binding declared here but left uninitialized LL | let y = x as *const i32; - | ^ use of possibly-uninitialized `*x` + | ^ `*x` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while-break.rs b/src/test/ui/borrowck/borrowck-while-break.rs index 48e4221470221..7100b713031d2 100644 --- a/src/test/ui/borrowck/borrowck-while-break.rs +++ b/src/test/ui/borrowck/borrowck-while-break.rs @@ -4,7 +4,7 @@ fn test(cond: bool) { v = 3; break; } - println!("{}", v); //~ ERROR borrow of possibly-uninitialized variable: `v` + println!("{}", v); //~ ERROR E0381 } fn main() { diff --git a/src/test/ui/borrowck/borrowck-while-break.stderr b/src/test/ui/borrowck/borrowck-while-break.stderr index fc144a066bb27..44674febf4973 100644 --- a/src/test/ui/borrowck/borrowck-while-break.stderr +++ b/src/test/ui/borrowck/borrowck-while-break.stderr @@ -1,8 +1,13 @@ -error[E0381]: borrow of possibly-uninitialized variable: `v` +error[E0381]: used binding `v` is possibly-uninitialized --> $DIR/borrowck-while-break.rs:7:20 | +LL | let v; + | - binding declared here but left uninitialized +LL | while cond { + | ---- if this condition isn't met and the `while` loop runs 0 times, `v` is not initialized +... LL | println!("{}", v); - | ^ use of possibly-uninitialized `v` + | ^ `v` used here but it is possibly-uninitialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/borrowck/borrowck-while-cond.rs b/src/test/ui/borrowck/borrowck-while-cond.rs index b3ec20711c12b..62a9bdd202055 100644 --- a/src/test/ui/borrowck/borrowck-while-cond.rs +++ b/src/test/ui/borrowck/borrowck-while-cond.rs @@ -1,4 +1,4 @@ fn main() { let x: bool; - while x { } //~ ERROR use of possibly-uninitialized variable: `x` + while x { } //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/borrowck-while-cond.stderr b/src/test/ui/borrowck/borrowck-while-cond.stderr index 92937a9c5730e..e41c1c55e6024 100644 --- a/src/test/ui/borrowck/borrowck-while-cond.stderr +++ b/src/test/ui/borrowck/borrowck-while-cond.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/borrowck-while-cond.rs:3:11 | +LL | let x: bool; + | - binding declared here but left uninitialized LL | while x { } - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-while.rs b/src/test/ui/borrowck/borrowck-while.rs index 6b3220c7d8591..f49a778eb6bbe 100644 --- a/src/test/ui/borrowck/borrowck-while.rs +++ b/src/test/ui/borrowck/borrowck-while.rs @@ -1,7 +1,7 @@ fn f() -> isize { let mut x: isize; while 1 == 1 { x = 10; } - return x; //~ ERROR use of possibly-uninitialized variable: `x` + return x; //~ ERROR E0381 } fn main() { f(); } diff --git a/src/test/ui/borrowck/borrowck-while.stderr b/src/test/ui/borrowck/borrowck-while.stderr index a1f8f64725dcd..c45235990c383 100644 --- a/src/test/ui/borrowck/borrowck-while.stderr +++ b/src/test/ui/borrowck/borrowck-while.stderr @@ -1,8 +1,12 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` is possibly-uninitialized --> $DIR/borrowck-while.rs:4:12 | +LL | let mut x: isize; + | ----- binding declared here but left uninitialized +LL | while 1 == 1 { x = 10; } + | ------ if this condition isn't met and the `while` loop runs 0 times, `x` is not initialized LL | return x; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it is possibly-uninitialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/disallow-possibly-uninitialized.rs b/src/test/ui/borrowck/disallow-possibly-uninitialized.rs index 7043cb3a164e7..17de40d5ba967 100644 --- a/src/test/ui/borrowck/disallow-possibly-uninitialized.rs +++ b/src/test/ui/borrowck/disallow-possibly-uninitialized.rs @@ -4,19 +4,19 @@ fn main() { let mut t: (u64, u64); t.0 = 1; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + //~^ ERROR E0381 t.1 = 1; let mut t: (u64, u64); t.1 = 1; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + //~^ ERROR E0381 t.0 = 1; let mut t: (u64, u64); t.0 = 1; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + //~^ ERROR E0381 let mut t: (u64,); t.0 = 1; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + //~^ ERROR E0381 } diff --git a/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr b/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr index 8d5b39341c109..9a84c6fefae59 100644 --- a/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr +++ b/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr @@ -1,26 +1,42 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/disallow-possibly-uninitialized.rs:6:5 | +LL | let mut t: (u64, u64); + | ----- binding declared here but left uninitialized LL | t.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/disallow-possibly-uninitialized.rs:11:5 | +LL | let mut t: (u64, u64); + | ----- binding declared here but left uninitialized LL | t.1 = 1; - | ^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/disallow-possibly-uninitialized.rs:16:5 | +LL | let mut t: (u64, u64); + | ----- binding declared here but left uninitialized LL | t.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/disallow-possibly-uninitialized.rs:20:5 | +LL | let mut t: (u64,); + | ----- binding declared here but left uninitialized LL | t.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 4 previous errors diff --git a/src/test/ui/borrowck/issue-11493.fixed b/src/test/ui/borrowck/issue-11493.fixed new file mode 100644 index 0000000000000..139bd9a073973 --- /dev/null +++ b/src/test/ui/borrowck/issue-11493.fixed @@ -0,0 +1,9 @@ +// run-rustfix +fn id<T>(x: T) -> T { x } + +fn main() { + let x = Some(3); + let binding = id(5); + let y = x.as_ref().unwrap_or(&binding); //~ ERROR + let _ = &y; +} diff --git a/src/test/ui/issues/issue-11493.rs b/src/test/ui/borrowck/issue-11493.rs similarity index 78% rename from src/test/ui/issues/issue-11493.rs rename to src/test/ui/borrowck/issue-11493.rs index b28c173b19b71..cb77f89fb2b1e 100644 --- a/src/test/ui/issues/issue-11493.rs +++ b/src/test/ui/borrowck/issue-11493.rs @@ -1,7 +1,8 @@ +// run-rustfix fn id<T>(x: T) -> T { x } fn main() { let x = Some(3); let y = x.as_ref().unwrap_or(&id(5)); //~ ERROR - &y; + let _ = &y; } diff --git a/src/test/ui/issues/issue-11493.stderr b/src/test/ui/borrowck/issue-11493.stderr similarity index 64% rename from src/test/ui/issues/issue-11493.stderr rename to src/test/ui/borrowck/issue-11493.stderr index f954d64ac5bf4..a5d1f2816f1ca 100644 --- a/src/test/ui/issues/issue-11493.stderr +++ b/src/test/ui/borrowck/issue-11493.stderr @@ -1,14 +1,18 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-11493.rs:5:35 + --> $DIR/issue-11493.rs:6:35 | LL | let y = x.as_ref().unwrap_or(&id(5)); | ^^^^^ - temporary value is freed at the end of this statement | | | creates a temporary which is freed while still in use -LL | &y; - | -- borrow later used here +LL | let _ = &y; + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id(5); +LL ~ let y = x.as_ref().unwrap_or(&binding); | - = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.rs b/src/test/ui/borrowck/issue-24267-flow-exit.rs index d6809ee4143b0..c419c5840d9a8 100644 --- a/src/test/ui/borrowck/issue-24267-flow-exit.rs +++ b/src/test/ui/borrowck/issue-24267-flow-exit.rs @@ -9,11 +9,11 @@ pub fn main() { pub fn foo1() { let x: i32; loop { x = break; } - println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x` + println!("{}", x); //~ ERROR E0381 } pub fn foo2() { let x: i32; for _ in 0..10 { x = continue; } - println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x` + println!("{}", x); //~ ERROR E0381 } diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.stderr b/src/test/ui/borrowck/issue-24267-flow-exit.stderr index e29cf7a1a7519..d436e8ff9096c 100644 --- a/src/test/ui/borrowck/issue-24267-flow-exit.stderr +++ b/src/test/ui/borrowck/issue-24267-flow-exit.stderr @@ -1,16 +1,22 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/issue-24267-flow-exit.rs:12:20 | +LL | let x: i32; + | - binding declared here but left uninitialized +LL | loop { x = break; } LL | println!("{}", x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/issue-24267-flow-exit.rs:18:20 | +LL | let x: i32; + | - binding declared here but left uninitialized +LL | for _ in 0..10 { x = continue; } LL | println!("{}", x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/borrowck/issue-36082.fixed b/src/test/ui/borrowck/issue-36082.fixed new file mode 100644 index 0000000000000..8640ca7a50964 --- /dev/null +++ b/src/test/ui/borrowck/issue-36082.fixed @@ -0,0 +1,17 @@ +// run-rustfix +use std::cell::RefCell; + +fn main() { + let mut r = 0; + let s = 0; + let x = RefCell::new((&mut r,s)); + + let binding = x.borrow(); + let val: &_ = binding.0; + //~^ ERROR temporary value dropped while borrowed [E0716] + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE creates a temporary which is freed while still in use + //~| HELP consider using a `let` binding to create a longer lived value + println!("{}", val); + //~^ borrow later used here +} diff --git a/src/test/ui/issues/issue-36082.rs b/src/test/ui/borrowck/issue-36082.rs similarity index 83% rename from src/test/ui/issues/issue-36082.rs rename to src/test/ui/borrowck/issue-36082.rs index a2ff477eb816a..877d372fb8484 100644 --- a/src/test/ui/issues/issue-36082.rs +++ b/src/test/ui/borrowck/issue-36082.rs @@ -1,3 +1,4 @@ +// run-rustfix use std::cell::RefCell; fn main() { @@ -9,7 +10,7 @@ fn main() { //~^ ERROR temporary value dropped while borrowed [E0716] //~| NOTE temporary value is freed at the end of this statement //~| NOTE creates a temporary which is freed while still in use - //~| NOTE consider using a `let` binding to create a longer lived value + //~| HELP consider using a `let` binding to create a longer lived value println!("{}", val); //~^ borrow later used here } diff --git a/src/test/ui/issues/issue-36082.stderr b/src/test/ui/borrowck/issue-36082.stderr similarity index 73% rename from src/test/ui/issues/issue-36082.stderr rename to src/test/ui/borrowck/issue-36082.stderr index 26bf4cb1be8be..4bd586db1cdce 100644 --- a/src/test/ui/issues/issue-36082.stderr +++ b/src/test/ui/borrowck/issue-36082.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-36082.rs:8:19 + --> $DIR/issue-36082.rs:9:19 | LL | let val: &_ = x.borrow().0; | ^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -9,7 +9,11 @@ LL | let val: &_ = x.borrow().0; LL | println!("{}", val); | --- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = x.borrow(); +LL ~ let val: &_ = binding.0; + | error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr index a7c3b9eec73c5..d98b3bae4e0b3 100644 --- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr +++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | let _action = move || { | ------- | | | - | | return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]` contains a lifetime `'2` + | | return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:11]` contains a lifetime `'2` | lifetime `'1` represents this closure's body LL | || f() // The `nested` closure | ^^^^^^ returning this value requires that `'1` must outlive `'2` diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs index f031a144443b3..205ea10c90bf0 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs @@ -10,7 +10,7 @@ fn main() { { let mut t: Tuple; t.0 = S(1); - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + //~^ ERROR E0381 t.1 = 2; println!("{:?} {:?}", t.0, t.1); } @@ -18,7 +18,7 @@ fn main() { { let mut u: Tpair; u.0 = S(1); - //~^ ERROR assign to part of possibly-uninitialized variable: `u` [E0381] + //~^ ERROR E0381 u.1 = 2; println!("{:?} {:?}", u.0, u.1); } @@ -26,7 +26,7 @@ fn main() { { let mut v: Spair; v.x = S(1); - //~^ ERROR assign to part of possibly-uninitialized variable: `v` [E0381] + //~^ ERROR E0381 v.y = 2; println!("{:?} {:?}", v.x, v.y); } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr index 22c6c3964edc1..2a0eba396f144 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr +++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr @@ -1,20 +1,32 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:12:9 | +LL | let mut t: Tuple; + | ----- binding declared here but left uninitialized LL | t.0 = S(1); - | ^^^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `u` +error[E0381]: partially assigned binding `u` isn't fully initialized --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:20:9 | +LL | let mut u: Tpair; + | ----- binding declared here but left uninitialized LL | u.0 = S(1); - | ^^^^^^^^^^ use of possibly-uninitialized `u` + | ^^^^^^^^^^ `u` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `v` +error[E0381]: partially assigned binding `v` isn't fully initialized --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:28:9 | +LL | let mut v: Spair; + | ----- binding declared here but left uninitialized LL | v.x = S(1); - | ^^^^^^^^^^ use of possibly-uninitialized `v` + | ^^^^^^^^^^ `v` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs index 660d9e85ef54e..50d0c40fdf6f5 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs @@ -10,7 +10,7 @@ fn main() { { let t: Tuple; t.0 = S(1); - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + //~^ ERROR E0381 t.1 = 2; println!("{:?} {:?}", t.0, t.1); } @@ -18,7 +18,7 @@ fn main() { { let u: Tpair; u.0 = S(1); - //~^ ERROR assign to part of possibly-uninitialized variable: `u` [E0381] + //~^ ERROR E0381 u.1 = 2; println!("{:?} {:?}", u.0, u.1); } @@ -26,7 +26,7 @@ fn main() { { let v: Spair; v.x = S(1); - //~^ ERROR assign to part of possibly-uninitialized variable: `v` [E0381] + //~^ ERROR E0381 v.y = 2; println!("{:?} {:?}", v.x, v.y); } diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr index 5f9c978c342f6..67a62583057f6 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr @@ -1,20 +1,32 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/issue-54499-field-mutation-of-never-init.rs:12:9 | +LL | let t: Tuple; + | - binding declared here but left uninitialized LL | t.0 = S(1); - | ^^^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `u` +error[E0381]: partially assigned binding `u` isn't fully initialized --> $DIR/issue-54499-field-mutation-of-never-init.rs:20:9 | +LL | let u: Tpair; + | - binding declared here but left uninitialized LL | u.0 = S(1); - | ^^^^^^^^^^ use of possibly-uninitialized `u` + | ^^^^^^^^^^ `u` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `v` +error[E0381]: partially assigned binding `v` isn't fully initialized --> $DIR/issue-54499-field-mutation-of-never-init.rs:28:9 | +LL | let v: Spair; + | - binding declared here but left uninitialized LL | v.x = S(1); - | ^^^^^^^^^^ use of possibly-uninitialized `v` + | ^^^^^^^^^^ `v` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs index f8efa8c891eb3..93ce34d2fe535 100644 --- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs +++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs @@ -1,7 +1,7 @@ fn main() { let e: i32; match e { - //~^ ERROR use of possibly-uninitialized variable + //~^ ERROR E0381 ref u if true => {} ref v if true => { let tx = 0; diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr index 0eca447b55159..f5d2eecfa91a3 100644 --- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr +++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `e` +error[E0381]: used binding `e` isn't initialized --> $DIR/issue-62107-match-arm-scopes.rs:3:11 | +LL | let e: i32; + | - binding declared here but left uninitialized LL | match e { - | ^ use of possibly-uninitialized `e` + | ^ `e` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-1.stderr b/src/test/ui/borrowck/issue-81365-1.stderr index ef88d7f14a39b..d79394834dcad 100644 --- a/src/test/ui/borrowck/issue-81365-1.stderr +++ b/src/test/ui/borrowck/issue-81365-1.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-1.rs:12:5 | LL | type Target = DerefTarget; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-2.stderr b/src/test/ui/borrowck/issue-81365-2.stderr index e71edb509649f..764eaaa7cc7b4 100644 --- a/src/test/ui/borrowck/issue-81365-2.stderr +++ b/src/test/ui/borrowck/issue-81365-2.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-2.rs:12:5 | LL | type Target = DerefTarget; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-3.stderr b/src/test/ui/borrowck/issue-81365-3.stderr index 70bb6bb93a94b..9447174fd21ea 100644 --- a/src/test/ui/borrowck/issue-81365-3.stderr +++ b/src/test/ui/borrowck/issue-81365-3.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-3.rs:23:5 | LL | type Target = Container; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-4.stderr b/src/test/ui/borrowck/issue-81365-4.stderr index e714bb86d1cd2..0ab3fa92706b0 100644 --- a/src/test/ui/borrowck/issue-81365-4.stderr +++ b/src/test/ui/borrowck/issue-81365-4.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-4.rs:24:5 | LL | type Target = Container; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-5.stderr b/src/test/ui/borrowck/issue-81365-5.stderr index 8201894c6db4c..20ff229ffe7dd 100644 --- a/src/test/ui/borrowck/issue-81365-5.stderr +++ b/src/test/ui/borrowck/issue-81365-5.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-5.rs:19:5 | LL | type Target = DerefTarget; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-6.stderr b/src/test/ui/borrowck/issue-81365-6.stderr index 85ed6acca3d41..575aed73b4663 100644 --- a/src/test/ui/borrowck/issue-81365-6.stderr +++ b/src/test/ui/borrowck/issue-81365-6.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-6.rs:9:5 | LL | type Target = [()]; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-7.stderr b/src/test/ui/borrowck/issue-81365-7.stderr index 506732ec0c5b4..52d2d9e75a951 100644 --- a/src/test/ui/borrowck/issue-81365-7.stderr +++ b/src/test/ui/borrowck/issue-81365-7.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-7.rs:12:5 | LL | type Target = DerefTarget; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81365-8.stderr b/src/test/ui/borrowck/issue-81365-8.stderr index 716b6e9b51fd0..fd83e10a295dc 100644 --- a/src/test/ui/borrowck/issue-81365-8.stderr +++ b/src/test/ui/borrowck/issue-81365-8.stderr @@ -13,7 +13,7 @@ note: deref defined here --> $DIR/issue-81365-8.rs:12:5 | LL | type Target = DerefTarget; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-81899.stderr b/src/test/ui/borrowck/issue-81899.stderr index 92ebd5a220d90..1acabefb893e3 100644 --- a/src/test/ui/borrowck/issue-81899.stderr +++ b/src/test/ui/borrowck/issue-81899.stderr @@ -8,7 +8,7 @@ LL | panic!() | ^^^^^^^^ | | | the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:12:5 - | inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL + | inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:34]>` at $SRC_DIR/std/src/panic.rs:LL:COL | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,9 +16,7 @@ error: any use of this value will cause an error --> $DIR/issue-81899.rs:4:23 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ----------------------^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | ------------------- ^^^^^^^^^^^^^^^ referenced constant has errors | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -27,3 +25,14 @@ LL | const _CONST: &[u8] = &f(&[], |_| {}); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/issue-81899.rs:4:23 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | ------------------- ^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs index dd0320bc53ba7..2c8a700bc2ea3 100644 --- a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs +++ b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs @@ -17,6 +17,7 @@ async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> { //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied //~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied LockedMarket(generator.lock().unwrap().buy()) + //~^ ERROR cannot return value referencing temporary } struct LockedMarket<T>(T); diff --git a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr index d2b927fb664c6..4bd0667304397 100644 --- a/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr +++ b/src/test/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr @@ -7,7 +7,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> | expected 0 lifetime arguments | note: struct defined here, with 0 lifetime parameters - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 | LL | struct LockedMarket<T>(T); | ^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> | ^^^^^^^^^^^^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:23:8 | LL | struct LockedMarket<T>(T); | ^^^^^^^^^^^^ - @@ -28,6 +28,16 @@ help: add missing generic argument LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> { | +++ -error: aborting due to 2 previous errors +error[E0515]: cannot return value referencing temporary value + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:19:5 + | +LL | LockedMarket(generator.lock().unwrap().buy()) + | ^^^^^^^^^^^^^-------------------------^^^^^^^ + | | | + | | temporary value created here + | returns a value referencing data owned by the current function + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0515. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/borrowck/issue-85765.rs b/src/test/ui/borrowck/issue-85765.rs index 2b1ab2f705057..1598cd5d3c86f 100644 --- a/src/test/ui/borrowck/issue-85765.rs +++ b/src/test/ui/borrowck/issue-85765.rs @@ -1,7 +1,7 @@ fn main() { let mut test = Vec::new(); let rofl: &Vec<Vec<i32>> = &mut test; - //~^ HELP consider changing this to be a mutable reference + //~^ NOTE consider changing this binding's type to be rofl.push(Vec::new()); //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -15,14 +15,14 @@ fn main() { #[rustfmt::skip] let x: &usize = &mut{0}; - //~^ HELP consider changing this to be a mutable reference + //~^ NOTE consider changing this binding's type to be *x = 1; //~^ ERROR cannot assign to `*x`, which is behind a `&` reference //~| NOTE `x` is a `&` reference, so the data it refers to cannot be written #[rustfmt::skip] let y: &usize = &mut(0); - //~^ HELP consider changing this to be a mutable reference + //~^ NOTE consider changing this binding's type to be *y = 1; //~^ ERROR cannot assign to `*y`, which is behind a `&` reference //~| NOTE `y` is a `&` reference, so the data it refers to cannot be written diff --git a/src/test/ui/borrowck/issue-85765.stderr b/src/test/ui/borrowck/issue-85765.stderr index 80acaa7d21c52..13033962142fa 100644 --- a/src/test/ui/borrowck/issue-85765.stderr +++ b/src/test/ui/borrowck/issue-85765.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference --> $DIR/issue-85765.rs:5:5 | LL | let rofl: &Vec<Vec<i32>> = &mut test; - | ---- help: consider changing this to be a mutable reference: `&mut Vec<Vec<i32>>` + | ---- consider changing this binding's type to be: `&mut Vec<Vec<i32>>` LL | LL | rofl.push(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -20,7 +20,7 @@ error[E0594]: cannot assign to `*x`, which is behind a `&` reference --> $DIR/issue-85765.rs:19:5 | LL | let x: &usize = &mut{0}; - | - help: consider changing this to be a mutable reference: `&mut usize` + | - consider changing this binding's type to be: `&mut usize` LL | LL | *x = 1; | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written @@ -29,7 +29,7 @@ error[E0594]: cannot assign to `*y`, which is behind a `&` reference --> $DIR/issue-85765.rs:26:5 | LL | let y: &usize = &mut(0); - | - help: consider changing this to be a mutable reference: `&mut usize` + | - consider changing this binding's type to be: `&mut usize` LL | LL | *y = 1; | ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written diff --git a/src/test/ui/borrowck/issue-87456-point-to-closure.stderr b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr index fd38ad7bb0a7f..039575a8d79a5 100644 --- a/src/test/ui/borrowck/issue-87456-point-to-closure.stderr +++ b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr @@ -1,21 +1,17 @@ error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure --> $DIR/issue-87456-point-to-closure.rs:10:28 | -LL | let val = String::new(); - | --- captured outer variable +LL | let val = String::new(); + | --- captured outer variable LL | -LL | take_mut(|| { - | ______________- -LL | | -LL | | let _foo: String = val; - | | ^^^ - | | | - | | move occurs because `val` has type `String`, which does not implement the `Copy` trait - | | help: consider borrowing here: `&val` -LL | | -LL | | -LL | | }) - | |_____- captured by this `FnMut` closure +LL | take_mut(|| { + | -- captured by this `FnMut` closure +LL | +LL | let _foo: String = val; + | ^^^ + | | + | move occurs because `val` has type `String`, which does not implement the `Copy` trait + | help: consider borrowing here: `&val` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-88434-minimal-example.stderr b/src/test/ui/borrowck/issue-88434-minimal-example.stderr index d46cd862e34aa..c7b5d773e8259 100644 --- a/src/test/ui/borrowck/issue-88434-minimal-example.stderr +++ b/src/test/ui/borrowck/issue-88434-minimal-example.stderr @@ -8,7 +8,7 @@ LL | panic!() | ^^^^^^^^ | | | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:11:5 - | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL + | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:28]>` at $SRC_DIR/std/src/panic.rs:LL:COL | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,9 +16,7 @@ error: any use of this value will cause an error --> $DIR/issue-88434-minimal-example.rs:3:21 | LL | const _CONST: &() = &f(&|_| {}); - | --------------------^^^^^^^^^^^- - | | - | referenced constant has errors + | ----------------- ^^^^^^^^^^^ referenced constant has errors | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -27,3 +25,14 @@ LL | const _CONST: &() = &f(&|_| {}); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/issue-88434-minimal-example.rs:3:21 + | +LL | const _CONST: &() = &f(&|_| {}); + | ----------------- ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr index e6b07aba74d42..f4bb895e6b5a0 100644 --- a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr +++ b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr @@ -8,7 +8,7 @@ LL | panic!() | ^^^^^^^^ | | | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:11:5 - | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL + | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:34]>` at $SRC_DIR/std/src/panic.rs:LL:COL | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -16,9 +16,7 @@ error: any use of this value will cause an error --> $DIR/issue-88434-removal-index-should-be-less.rs:3:23 | LL | const _CONST: &[u8] = &f(&[], |_| {}); - | ----------------------^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | ------------------- ^^^^^^^^^^^^^^^ referenced constant has errors | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -27,3 +25,14 @@ LL | const _CONST: &[u8] = &f(&[], |_| {}); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/issue-88434-removal-index-should-be-less.rs:3:23 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | ------------------- ^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/borrowck/issue-91206.rs b/src/test/ui/borrowck/issue-91206.rs index 3b1fbf4b69902..67407c1eae3cf 100644 --- a/src/test/ui/borrowck/issue-91206.rs +++ b/src/test/ui/borrowck/issue-91206.rs @@ -9,7 +9,8 @@ impl TestClient { fn main() { let client = TestClient; let inner = client.get_inner_ref(); - //~^ HELP consider changing this to be a mutable reference + //~^ NOTE consider changing this binding's type to be inner.clear(); //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596] + //~| NOTE `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable } diff --git a/src/test/ui/borrowck/issue-91206.stderr b/src/test/ui/borrowck/issue-91206.stderr index 535d247452a59..12d8d27c5f026 100644 --- a/src/test/ui/borrowck/issue-91206.stderr +++ b/src/test/ui/borrowck/issue-91206.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference --> $DIR/issue-91206.rs:13:5 | LL | let inner = client.get_inner_ref(); - | ----- help: consider changing this to be a mutable reference: `&mut Vec<usize>` + | ----- consider changing this binding's type to be: `&mut Vec<usize>` LL | LL | inner.clear(); | ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/borrowck/issue-92015.stderr b/src/test/ui/borrowck/issue-92015.stderr index 32a65d3b5bb0f..62b1183e71b4b 100644 --- a/src/test/ui/borrowck/issue-92015.stderr +++ b/src/test/ui/borrowck/issue-92015.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to `*foo`, which is behind a `&` reference --> $DIR/issue-92015.rs:6:5 | LL | let foo = Some(&0).unwrap(); - | --- help: consider changing this to be a mutable reference: `&mut i32` + | --- consider changing this binding's type to be: `&mut i32` LL | *foo = 1; | ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs index 8fbf120fc1c78..0bd2147f46331 100644 --- a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs @@ -1,8 +1,6 @@ // Moving from a reference/raw pointer should be an error, even when they're // the field of a union. -#![feature(untagged_unions)] - union Pointers { a: &'static String, b: &'static mut String, diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr index 82c3fe3b12d1c..70078582713c6 100644 --- a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -1,23 +1,23 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference - --> $DIR/move-from-union-field-issue-66500.rs:14:5 + --> $DIR/move-from-union-field-issue-66500.rs:12:5 | LL | *u.a | ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.b` which is behind a mutable reference - --> $DIR/move-from-union-field-issue-66500.rs:18:5 + --> $DIR/move-from-union-field-issue-66500.rs:16:5 | LL | *u.b | ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.c` which is behind a raw pointer - --> $DIR/move-from-union-field-issue-66500.rs:22:5 + --> $DIR/move-from-union-field-issue-66500.rs:20:5 | LL | *u.c | ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.d` which is behind a raw pointer - --> $DIR/move-from-union-field-issue-66500.rs:26:5 + --> $DIR/move-from-union-field-issue-66500.rs:24:5 | LL | *u.d | ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr index edab22569b34f..dd29ae492d604 100644 --- a/src/test/ui/borrowck/mutability-errors.stderr +++ b/src/test/ui/borrowck/mutability-errors.stderr @@ -119,146 +119,112 @@ LL | &mut (*f()).0; error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:40:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); - | | ^^^^^^^^ cannot assign -LL | | x.0 = 1; -LL | | &mut x; -LL | | &mut x.0; -LL | | }); - | |_____- in this closure +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); + | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:41:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); -LL | | x.0 = 1; - | | ^^^^^^^ cannot assign -LL | | &mut x; -LL | | &mut x.0; -LL | | }); - | |_____- in this closure +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); +LL | x.0 = 1; + | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:42:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); -LL | | x.0 = 1; -LL | | &mut x; - | | ^^^^^^ cannot borrow as mutable -LL | | &mut x.0; -LL | | }); - | |_____- in this closure +LL | &mut x; + | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:43:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); -LL | | x.0 = 1; -LL | | &mut x; -LL | | &mut x.0; - | | ^^^^^^^^ cannot borrow as mutable -LL | | }); - | |_____- in this closure +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:46:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); - | | ^^^^^^^^ cannot assign -LL | | x.0 = 1; -LL | | &mut x; -LL | | &mut x.0; -LL | | }); - | |_____- in this closure +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); + | ^^^^^^^^ cannot assign error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:47:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); -LL | | x.0 = 1; - | | ^^^^^^^ cannot assign -LL | | &mut x; -LL | | &mut x.0; -LL | | }); - | |_____- in this closure +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); +LL | x.0 = 1; + | ^^^^^^^ cannot assign error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/mutability-errors.rs:48:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); -LL | | x.0 = 1; -LL | | &mut x; - | | ^^^^^^ cannot borrow as mutable -LL | | &mut x.0; -LL | | }); - | |_____- in this closure +LL | &mut x; + | ^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables --> $DIR/mutability-errors.rs:49:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | x = (1,); -LL | | x.0 = 1; -LL | | &mut x; -LL | | &mut x.0; - | | ^^^^^^^^ cannot borrow as mutable -LL | | }); - | |_____- in this closure +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/mutability-errors.rs:54:5 diff --git a/src/test/ui/borrowck/reassignment_immutable_fields.stderr b/src/test/ui/borrowck/reassignment_immutable_fields.stderr index f09db378a75b4..e6b25573e7040 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields.stderr @@ -1,14 +1,22 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/reassignment_immutable_fields.rs:7:5 | +LL | let x: (u32, u32); + | - binding declared here but left uninitialized LL | x.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/reassignment_immutable_fields.rs:15:5 | +LL | let x: (u32, u32); + | - binding declared here but left uninitialized LL | x.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr index 0eae2c71e4a19..a3885b5f5caea 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr @@ -1,8 +1,12 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5 | +LL | let x: Foo; + | - binding declared here but left uninitialized LL | x.a = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5 diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr index f55e1a27f475e..49c81adad4937 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr @@ -7,11 +7,15 @@ LL | x = (22, 44); LL | x.0 = 1; | ^^^^^^^ cannot assign -error[E0381]: assign to part of possibly-uninitialized variable: `x` +error[E0381]: partially assigned binding `x` isn't fully initialized --> $DIR/reassignment_immutable_fields_twice.rs:12:5 | +LL | let x: (u32, u32); + | - binding declared here but left uninitialized LL | x.0 = 1; - | ^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^ `x` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.rs b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.rs new file mode 100644 index 0000000000000..1dcf04618796e --- /dev/null +++ b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.rs @@ -0,0 +1,16 @@ +// This is not exactly right, yet. + +// Ideally we should be suggesting `as_mut` for the first case, +// and suggesting to change `as_ref` to `as_mut` in the second. + +fn x(cb: &mut Option<&mut dyn FnMut()>) { + cb.map(|cb| cb()); + //~^ ERROR cannot move out of `*cb` which is behind a mutable reference +} + +fn x2(cb: &mut Option<&mut dyn FnMut()>) { + cb.as_ref().map(|cb| cb()); + //~^ ERROR cannot borrow `*cb` as mutable, as it is behind a `&` reference +} + +fn main() {} diff --git a/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr new file mode 100644 index 0000000000000..af26169c80681 --- /dev/null +++ b/src/test/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -0,0 +1,31 @@ +error[E0507]: cannot move out of `*cb` which is behind a mutable reference + --> $DIR/suggest-as-ref-on-mut-closure.rs:7:5 + | +LL | cb.map(|cb| cb()); + | ^^^-------------- + | | | + | | `*cb` moved due to this method call + | move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait + | +note: this function takes ownership of the receiver `self`, which moves `*cb` + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub const fn map<U, F>(self, f: F) -> Option<U> + | ^^^^ +help: consider calling `.as_ref()` to borrow the type's contents + | +LL | cb.as_ref().map(|cb| cb()); + | +++++++++ + +error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference + --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 + | +LL | cb.as_ref().map(|cb| cb()); + | -- ^^ `cb` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut &mut dyn FnMut()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index 3ea7226200362..0c151b097077e 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -1,17 +1,14 @@ error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9 | -LL | let y = vec![format!("World")]; - | - captured outer variable -LL | call(|| { - | __________- -LL | | y.into_iter(); - | | ^ ----------- `y` moved due to this method call - | | | - | | move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait -LL | | -LL | | }); - | |_____- captured by this `Fn` closure +LL | let y = vec![format!("World")]; + | - captured outer variable +LL | call(|| { + | -- captured by this `Fn` closure +LL | y.into_iter(); + | ^ ----------- `y` moved due to this method call + | | + | move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait | note: this function takes ownership of the receiver `self`, which moves `y` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL diff --git a/src/test/ui/cast/issue-85586.stderr b/src/test/ui/cast/issue-85586.stderr index 271885a133a95..ed8a6fc62e9dd 100644 --- a/src/test/ui/cast/issue-85586.stderr +++ b/src/test/ui/cast/issue-85586.stderr @@ -3,8 +3,6 @@ error[E0282]: type annotations needed | LL | let b = (a + 1) as usize; | ^^^^^^^ cannot infer type - | - = note: type must be known at this point error: aborting due to previous error diff --git a/src/test/ui/chalkify/bugs/async.rs b/src/test/ui/chalkify/bugs/async.rs index 58fc93064edf5..ae5224dbd6fa8 100644 --- a/src/test/ui/chalkify/bugs/async.rs +++ b/src/test/ui/chalkify/bugs/async.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: unknown // compile-flags: -Z chalk --edition=2021 fn main() -> () {} diff --git a/src/test/ui/chalkify/bugs/async.stderr b/src/test/ui/chalkify/bugs/async.stderr index 5b7ca8d46cf44..f53ed53f73c49 100644 --- a/src/test/ui/chalkify/bugs/async.stderr +++ b/src/test/ui/chalkify/bugs/async.stderr @@ -29,13 +29,10 @@ LL | T: Generator<ResumeTy, Yield = ()>, | ^^^^^^^^^^ required by this bound in `std::future::from_generator` error[E0280]: the requirement `<impl Future<Output = u32> as Future>::Output == u32` is not satisfied - --> $DIR/async.rs:7:29 + --> $DIR/async.rs:7:25 | -LL | async fn foo(x: u32) -> u32 { - | _____________________________^ -LL | | x -LL | | } - | |_^ +LL | async fn foo(x: u32) -> u32 { + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/cleanup-rvalue-scopes-cf.stderr b/src/test/ui/cleanup-rvalue-scopes-cf.stderr index 04e599755fb29..40f14c389842e 100644 --- a/src/test/ui/cleanup-rvalue-scopes-cf.stderr +++ b/src/test/ui/cleanup-rvalue-scopes-cf.stderr @@ -9,7 +9,11 @@ LL | let x1 = arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x1 = arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:27:14 @@ -22,7 +26,11 @@ LL | let x2 = AddFlags(1).get(); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x2 = binding.get(); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:28:21 @@ -35,7 +43,11 @@ LL | let x3 = &*arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x3 = &*arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:29:24 @@ -48,7 +60,11 @@ LL | let ref x4 = *arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let ref x4 = *arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:30:24 @@ -61,7 +77,11 @@ LL | let &ref x5 = arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let &ref x5 = arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:31:14 @@ -74,7 +94,11 @@ LL | let x6 = AddFlags(1).get(); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x6 = binding.get(); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:32:44 @@ -87,7 +111,11 @@ LL | LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let StackBox { f: x7 } = StackBox { f: binding.get() }; + | error: aborting due to 7 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr b/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr index 57b8f7ae60978..5696a010c3f80 100644 --- a/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr +++ b/src/test/ui/closures/2229_closure_analysis/issue-87987.stderr @@ -4,9 +4,9 @@ warning: fields `field_1` and `field_2` are never read LL | struct Props { | ----- fields in this struct LL | field_1: u32, - | ^^^^^^^^^^^^ + | ^^^^^^^ LL | field_2: u32, - | ^^^^^^^^^^^^ + | ^^^^^^^ | = note: `#[warn(dead_code)]` on by default diff --git a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr index 32d36274ff6ef..e0678bc718fa0 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr +++ b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr @@ -25,7 +25,7 @@ note: `E1` defined here --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1 | LL | pub enum E1 {} - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ = note: the matched value is of type `E1`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -44,7 +44,7 @@ note: `E2` defined here --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1 | LL | pub enum E2 { A, B } - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ = note: the matched value is of type `E2`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs index 0f288ffa95a87..69cf920de9478 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs +++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs @@ -6,14 +6,14 @@ fn test1() { let x: !; let c1 = || match x { }; - //~^ ERROR: use of possibly-uninitialized variable: `x` + //~^ ERROR E0381 } // Should fake read the discriminant and throw an error fn test2() { let x: !; let c2 = || match x { _ => () }; - //~^ ERROR: borrow of possibly-uninitialized variable: `x` + //~^ ERROR E0381 } // Testing single variant patterns @@ -25,7 +25,7 @@ enum SingleVariant { fn test3() { let variant: !; let c = || { - //~^ ERROR: borrow of possibly-uninitialized variable: `variant` + //~^ ERROR E0381 match variant { SingleVariant::Points(_) => {} } @@ -36,8 +36,7 @@ fn test3() { // Should fake read the discriminant and throw an error fn test4() { let variant: !; - let c = || { - //~^ ERROR: borrow of possibly-uninitialized variable: `variant` + let c = || { //~ ERROR E0381 match variant { SingleVariant::Points(a) => { println!("{:?}", a); @@ -52,11 +51,9 @@ fn test5() { let g: !; let a = || { - match g { }; - //~^ ERROR: use of possibly-uninitialized variable: `g` + match g { }; //~ ERROR E0381 let c = || { - match t { }; - //~^ ERROR: use of possibly-uninitialized variable: `t` + match t { }; //~ ERROR E0381 }; c(); @@ -68,7 +65,7 @@ fn test5() { fn test6() { let x: u8; let c1 = || match x { }; - //~^ ERROR: use of possibly-uninitialized variable: `x` + //~^ ERROR E0381 //~| ERROR: non-exhaustive patterns: type `u8` is non-empty } diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr index e55fb7ce4bbe9..fea5441ec673d 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr +++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/pattern-matching-should-fail.rs:70:23 + --> $DIR/pattern-matching-should-fail.rs:67:23 | LL | let c1 = || match x { }; | ^ @@ -12,55 +12,70 @@ LL + _ => todo!(), LL ~ }; | -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/pattern-matching-should-fail.rs:8:23 | +LL | let x: !; + | - binding declared here but left uninitialized LL | let c1 = || match x { }; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/pattern-matching-should-fail.rs:15:14 | +LL | let x: !; + | - binding declared here but left uninitialized LL | let c2 = || match x { _ => () }; | ^^ - borrow occurs due to use in closure | | - | use of possibly-uninitialized `x` + | `x` used here but it isn't initialized -error[E0381]: borrow of possibly-uninitialized variable: `variant` +error[E0381]: used binding `variant` isn't initialized --> $DIR/pattern-matching-should-fail.rs:27:13 | +LL | let variant: !; + | ------- binding declared here but left uninitialized LL | let c = || { - | ^^ use of possibly-uninitialized `variant` + | ^^ `variant` used here but it isn't initialized LL | LL | match variant { | ------- borrow occurs due to use in closure -error[E0381]: borrow of possibly-uninitialized variable: `variant` +error[E0381]: used binding `variant` isn't initialized --> $DIR/pattern-matching-should-fail.rs:39:13 | +LL | let variant: !; + | ------- binding declared here but left uninitialized LL | let c = || { - | ^^ use of possibly-uninitialized `variant` -LL | + | ^^ `variant` used here but it isn't initialized LL | match variant { | ------- borrow occurs due to use in closure -error[E0381]: use of possibly-uninitialized variable: `g` - --> $DIR/pattern-matching-should-fail.rs:55:15 +error[E0381]: used binding `g` isn't initialized + --> $DIR/pattern-matching-should-fail.rs:54:15 | +LL | let g: !; + | - binding declared here but left uninitialized +... LL | match g { }; - | ^ use of possibly-uninitialized `g` + | ^ `g` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `t` - --> $DIR/pattern-matching-should-fail.rs:58:19 +error[E0381]: used binding `t` isn't initialized + --> $DIR/pattern-matching-should-fail.rs:56:19 | +LL | let t: !; + | - binding declared here but left uninitialized +... LL | match t { }; - | ^ use of possibly-uninitialized `t` + | ^ `t` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/pattern-matching-should-fail.rs:70:23 +error[E0381]: used binding `x` isn't initialized + --> $DIR/pattern-matching-should-fail.rs:67:23 | +LL | let x: u8; + | - binding declared here but left uninitialized LL | let c1 = || match x { }; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error: aborting due to 8 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index a3c43690f1f32..d7104bafeb1d0 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -2,7 +2,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send` + | ^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send` ... LL | *fptr.0 = 20; | ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0` @@ -26,7 +26,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ + | ^^^^^^^ | | | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send` | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr index 675ba0313d73e..c611daf13fda4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr @@ -2,14 +2,10 @@ warning: changes to closure capture in Rust 2021 will affect drop order --> $DIR/closure-body-macro-fragment.rs:16:17 | LL | let f = || $body; - | _________________^ -LL | | -LL | | f(); -LL | | }}; - | | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure -LL | | ($body:block) => {{ -LL | | m!(@ $body); - | |__________________^ + | ^^ +... +LL | }}; + | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure ... LL | / m!({ LL | | diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr index 5046a4bcbb4b3..2d0c56aad8d62 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr @@ -2,9 +2,7 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/macro.rs:19:13 | LL | let _ = || dbg!(a.0); - | ^^^^^^^^---^ - | | - | in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0` + | ^^ --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0` ... LL | } | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr index 3589a6150d064..12760cc7256c9 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr @@ -26,9 +26,7 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/migrations_rustfix.rs:33:13 | LL | let c = || t.0; - | ^^^--- - | | - | in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` + | ^^ --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` ... LL | } | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index fa6082cbb59b4..96d5c936fa593 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -92,7 +92,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos --> $DIR/multi_diagnostics.rs:133:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ + | ^^^^^^^ | | | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send` | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr index fa1f83c37823f..0d9f09ee354ed 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -199,9 +199,7 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:201:18 | LL | let _c = || tup.0; - | ^^^----- - | | - | in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` + | ^^ ----- in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` ... LL | } | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure diff --git a/src/test/ui/closures/binder/async-closure-with-binder.rs b/src/test/ui/closures/binder/async-closure-with-binder.rs new file mode 100644 index 0000000000000..4fa599d37cbd1 --- /dev/null +++ b/src/test/ui/closures/binder/async-closure-with-binder.rs @@ -0,0 +1,8 @@ +// edition:2021 +#![feature(closure_lifetime_binder)] +#![feature(async_closure)] +fn main() { + for<'a> async || (); + //~^ ERROR `for<...>` binders on `async` closures are not currently supported + //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present +} diff --git a/src/test/ui/closures/binder/async-closure-with-binder.stderr b/src/test/ui/closures/binder/async-closure-with-binder.stderr new file mode 100644 index 0000000000000..1d4628b1a494a --- /dev/null +++ b/src/test/ui/closures/binder/async-closure-with-binder.stderr @@ -0,0 +1,16 @@ +error: `for<...>` binders on `async` closures are not currently supported + --> $DIR/async-closure-with-binder.rs:5:5 + | +LL | for<'a> async || (); + | ^^^^^^^ + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/async-closure-with-binder.rs:5:5 + | +LL | for<'a> async || (); + | -------^^^^^^^^^ + | | + | `for<...>` is here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/closures/binder/implicit-return.rs b/src/test/ui/closures/binder/implicit-return.rs new file mode 100644 index 0000000000000..d34e5721d919b --- /dev/null +++ b/src/test/ui/closures/binder/implicit-return.rs @@ -0,0 +1,6 @@ +#![feature(closure_lifetime_binder)] + +fn main() { + let _f = for<'a> |_: &'a ()| {}; + //~^ implicit types in closure signatures are forbidden when `for<...>` is present +} diff --git a/src/test/ui/closures/binder/implicit-return.stderr b/src/test/ui/closures/binder/implicit-return.stderr new file mode 100644 index 0000000000000..5bfb97113344a --- /dev/null +++ b/src/test/ui/closures/binder/implicit-return.stderr @@ -0,0 +1,10 @@ +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-return.rs:4:34 + | +LL | let _f = for<'a> |_: &'a ()| {}; + | ------- ^ + | | + | `for<...>` is here + +error: aborting due to previous error + diff --git a/src/test/ui/closures/binder/implicit-stuff.rs b/src/test/ui/closures/binder/implicit-stuff.rs new file mode 100644 index 0000000000000..09e4c747afee8 --- /dev/null +++ b/src/test/ui/closures/binder/implicit-stuff.rs @@ -0,0 +1,27 @@ +#![feature(closure_lifetime_binder)] + +fn main() { + // Implicit types + let _ = for<> || {}; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> || -> &'a _ { &() }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> |x| -> &'a () { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> |x: &'a _| -> &'a () { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> |x: &'a Vec::<_>| -> &'a Vec::<()> { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> |x: &'a Vec<()>| -> &'a Vec<_> { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> |x: &'a _| -> &'a &'a () { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _ = for<'a> |x: &'a _, y, z: _| -> &'a _ { //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present + let _: &u8 = x; + let _: u32 = y; + let _: i32 = z; + x + }; + + // Lifetime elision + let _ = for<> |_: &()| -> () {}; //~ ERROR `&` without an explicit lifetime name cannot be used here + let _ = for<> |x: &()| -> &() { x }; //~ ERROR `&` without an explicit lifetime name cannot be used here + //~| ERROR `&` without an explicit lifetime name cannot be used here + let _ = for<> |x: &'_ ()| -> &'_ () { x }; //~ ERROR `'_` cannot be used here + //~| ERROR `'_` cannot be used here + let _ = for<'a> |x: &()| -> &'a () { x }; //~ ERROR `&` without an explicit lifetime name cannot be used here + let _ = for<'a> |x: &'a ()| -> &() { x }; //~ ERROR `&` without an explicit lifetime name cannot be used here +} diff --git a/src/test/ui/closures/binder/implicit-stuff.stderr b/src/test/ui/closures/binder/implicit-stuff.stderr new file mode 100644 index 0000000000000..779a08a44e5a8 --- /dev/null +++ b/src/test/ui/closures/binder/implicit-stuff.stderr @@ -0,0 +1,107 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/implicit-stuff.rs:20:23 + | +LL | let _ = for<> |_: &()| -> () {}; + | ^ explicit lifetime name needed here + +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/implicit-stuff.rs:21:23 + | +LL | let _ = for<> |x: &()| -> &() { x }; + | ^ explicit lifetime name needed here + +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/implicit-stuff.rs:21:31 + | +LL | let _ = for<> |x: &()| -> &() { x }; + | ^ explicit lifetime name needed here + +error[E0637]: `'_` cannot be used here + --> $DIR/implicit-stuff.rs:23:24 + | +LL | let _ = for<> |x: &'_ ()| -> &'_ () { x }; + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/implicit-stuff.rs:23:35 + | +LL | let _ = for<> |x: &'_ ()| -> &'_ () { x }; + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/implicit-stuff.rs:25:25 + | +LL | let _ = for<'a> |x: &()| -> &'a () { x }; + | ^ explicit lifetime name needed here + +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/implicit-stuff.rs:26:36 + | +LL | let _ = for<'a> |x: &'a ()| -> &() { x }; + | ^ explicit lifetime name needed here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:5:22 + | +LL | let _ = for<> || {}; + | ----- ^ + | | + | `for<...>` is here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:6:31 + | +LL | let _ = for<'a> || -> &'a _ { &() }; + | ------- ^ + | | + | `for<...>` is here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:7:22 + | +LL | let _ = for<'a> |x| -> &'a () { x }; + | ------- ^ + | | + | `for<...>` is here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:8:29 + | +LL | let _ = for<'a> |x: &'a _| -> &'a () { x }; + | ------- ^ + | | + | `for<...>` is here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:9:35 + | +LL | let _ = for<'a> |x: &'a Vec::<_>| -> &'a Vec::<()> { x }; + | ------- ^ + | | + | `for<...>` is here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:10:49 + | +LL | let _ = for<'a> |x: &'a Vec<()>| -> &'a Vec<_> { x }; + | ------- `for<...>` is here ^ + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:11:29 + | +LL | let _ = for<'a> |x: &'a _| -> &'a &'a () { x }; + | ------- ^ + | | + | `for<...>` is here + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/implicit-stuff.rs:12:29 + | +LL | let _ = for<'a> |x: &'a _, y, z: _| -> &'a _ { + | ------- ^ ^ ^ ^ + | | + | `for<...>` is here + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs new file mode 100644 index 0000000000000..b476dd50cc986 --- /dev/null +++ b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs @@ -0,0 +1,7 @@ +#![feature(closure_lifetime_binder)] +fn main() { + for<> |_: &'a ()| -> () {}; + //~^ ERROR use of undeclared lifetime name `'a` + for<'a> |_: &'b ()| -> () {}; + //~^ ERROR use of undeclared lifetime name `'b` +} diff --git a/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr new file mode 100644 index 0000000000000..1381acc15ca46 --- /dev/null +++ b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr @@ -0,0 +1,33 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/suggestion-for-introducing-lifetime-into-binder.rs:3:16 + | +LL | for<> |_: &'a ()| -> () {}; + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | for<'a, > |_: &'a ()| -> () {}; + | +++ +help: consider introducing lifetime `'a` here + | +LL | fn main<'a>() { + | ++++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/suggestion-for-introducing-lifetime-into-binder.rs:5:18 + | +LL | for<'a> |_: &'b ()| -> () {}; + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'b` here + | +LL | for<'b, 'a> |_: &'b ()| -> () {}; + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn main<'b>() { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr index cbc4e2e52315f..1086cfa2947a9 100644 --- a/src/test/ui/closures/closure-move-sync.stderr +++ b/src/test/ui/closures/closure-move-sync.stderr @@ -9,12 +9,8 @@ LL | let t = thread::spawn(|| { note: required because it's used within this closure --> $DIR/closure-move-sync.rs:6:27 | -LL | let t = thread::spawn(|| { - | ___________________________^ -LL | | recv.recv().unwrap(); -LL | | -LL | | }); - | |_____^ +LL | let t = thread::spawn(|| { + | ^^ note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL | @@ -33,7 +29,7 @@ note: required because it's used within this closure --> $DIR/closure-move-sync.rs:18:19 | LL | thread::spawn(|| tx.send(()).unwrap()); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL | diff --git a/src/test/ui/closures/closure-no-fn-1.stderr b/src/test/ui/closures/closure-no-fn-1.stderr index 2b53802fea793..eab7482e6c4a1 100644 --- a/src/test/ui/closures/closure-no-fn-1.stderr +++ b/src/test/ui/closures/closure-no-fn-1.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50]` + found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:36]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-no-fn-1.rs:6:39 | diff --git a/src/test/ui/closures/closure-no-fn-2.stderr b/src/test/ui/closures/closure-no-fn-2.stderr index ed9f87a2c94a8..e1f0143abfe0a 100644 --- a/src/test/ui/closures/closure-no-fn-2.stderr +++ b/src/test/ui/closures/closure-no-fn-2.stderr @@ -7,7 +7,7 @@ LL | let bar: fn() -> u8 = || { b }; | expected due to this | = note: expected fn pointer `fn() -> u8` - found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35]` + found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:29]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-no-fn-2.rs:6:32 | diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr index 95683a786ba6a..6009389b1bb2c 100644 --- a/src/test/ui/closures/closure-no-fn-3.stderr +++ b/src/test/ui/closures/closure-no-fn-3.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37]` as `fn() -> u8` +error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:28: 6:30]` as `fn() -> u8` --> $DIR/closure-no-fn-3.rs:6:27 | LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8; diff --git a/src/test/ui/closures/closure-no-fn-4.stderr b/src/test/ui/closures/closure-no-fn-4.stderr index 89798ec5dd34f..d1b7048841a42 100644 --- a/src/test/ui/closures/closure-no-fn-4.stderr +++ b/src/test/ui/closures/closure-no-fn-4.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____- `match` arms have incompatible types | = note: expected fn pointer `fn(usize) -> usize` - found closure `[closure@$DIR/closure-no-fn-4.rs:5:18: 5:27]` + found closure `[closure@$DIR/closure-no-fn-4.rs:5:18: 5:21]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-no-fn-4.rs:5:26 | diff --git a/src/test/ui/closures/closure-no-fn-5.stderr b/src/test/ui/closures/closure-no-fn-5.stderr index 1f373f10489e6..a33b847ea92d9 100644 --- a/src/test/ui/closures/closure-no-fn-5.stderr +++ b/src/test/ui/closures/closure-no-fn-5.stderr @@ -7,7 +7,7 @@ LL | let bar: fn() -> u8 = || { a; b; c; d; e }; | expected due to this | = note: expected fn pointer `fn() -> u8` - found closure `[closure@$DIR/closure-no-fn-5.rs:10:27: 10:47]` + found closure `[closure@$DIR/closure-no-fn-5.rs:10:27: 10:29]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-no-fn-5.rs:10:32 | diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 534828ab348fd..9dfff8499fddd 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -2,14 +2,14 @@ error[E0308]: mismatched types --> $DIR/closure-reform-bad.rs:11:15 | LL | let f = |s: &str| println!("{}{}", s, string); - | ------------------------------------- the found closure + | --------- the found closure LL | call_bare(f) | --------- ^ expected fn pointer, found closure | | | arguments to this function are incorrect | = note: expected fn pointer `for<'r> fn(&'r str)` - found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50]` + found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:22]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-reform-bad.rs:10:43 | diff --git a/src/test/ui/closures/closure-wrong-kind.stderr b/src/test/ui/closures/closure-wrong-kind.stderr index 65026128ae622..35caf71a5e8c7 100644 --- a/src/test/ui/closures/closure-wrong-kind.stderr +++ b/src/test/ui/closures/closure-wrong-kind.stderr @@ -2,9 +2,8 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closur --> $DIR/closure-wrong-kind.rs:10:19 | LL | let closure = |_| foo(x); - | ^^^^^^^^-^ - | | | - | | closure is `FnOnce` because it moves the variable `x` out of its environment + | ^^^ - closure is `FnOnce` because it moves the variable `x` out of its environment + | | | this closure implements `FnOnce`, not `Fn` LL | bar(closure); | --- the requirement to implement `Fn` derives from here diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr index e25b33bbcdb06..ca8a43328a9e4 100644 --- a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____- `match` arms have incompatible types | = note: expected fn item `fn(i32, i32) -> i32 {add}` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:22]` error[E0308]: `match` arms have incompatible types --> $DIR/closure_cap_coerce_many_fail.rs:18:16 @@ -23,15 +23,15 @@ LL | | "+" => |a, b| (a + b) as i32, | | --------------------- | | | | | the expected closure - | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` + | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:22]` LL | | "-" => |a, b| (a - b + cap) as i32, | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]` + = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:22]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:22]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object @@ -44,15 +44,15 @@ LL | | "+" => |a, b| (a + b + cap) as i32, | | --------------------------- | | | | | the expected closure - | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]` + | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:22]` LL | | "-" => |a, b| (a - b) as i32, | | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]` + = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:22]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:22]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object @@ -65,15 +65,15 @@ LL | | "+" => |a, b| (a + b + cap) as i32, | | --------------------------- | | | | | the expected closure - | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]` + | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:22]` LL | | "-" => |a, b| (a - b + cap) as i32, | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]` + = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:22]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:22]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object diff --git a/src/test/ui/closures/print/closure-print-generic-1.stderr b/src/test/ui/closures/print/closure-print-generic-1.stderr index 43a12f675f562..b21734f025767 100644 --- a/src/test/ui/closures/print/closure-print-generic-1.stderr +++ b/src/test/ui/closures/print/closure-print-generic-1.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `c` --> $DIR/closure-print-generic-1.rs:17:5 | LL | let c = to_fn_once(move || { - | - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 14:6]`, which does not implement the `Copy` trait + | - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 12:31]`, which does not implement the `Copy` trait ... LL | c(); | --- `c` moved due to this call diff --git a/src/test/ui/closures/print/closure-print-generic-2.stderr b/src/test/ui/closures/print/closure-print-generic-2.stderr index 9c75d5a9023ed..e53277a9396f3 100644 --- a/src/test/ui/closures/print/closure-print-generic-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-2.stderr @@ -2,14 +2,14 @@ error[E0308]: mismatched types --> $DIR/closure-print-generic-2.rs:6:22 | LL | let c = || println!("{} {}", t, x); - | -------------------------- the found closure + | -- the found closure LL | let c1: () = c; | -- ^ expected `()`, found closure | | | expected due to this | = note: expected unit type `()` - found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:43]` + found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:19]` help: use parentheses to call this closure | LL | let c1: () = c(); diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index aee782a1c5b85..ff89dd340349b 100644 --- a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/closure-print-generic-trim-off-verbose-2.rs:9:23 | LL | let c = || println!("{} {}", t, x); - | -------------------------- the found closure + | -- the found closure LL | let c1 : () = c; | -- ^ expected `()`, found closure | | diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr index 6a994ce718eac..5bbf84f963d7e 100644 --- a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/closure-print-generic-verbose-2.rs:9:23 | LL | let c = || println!("{} {}", t, x); - | -------------------------- the found closure + | -- the found closure LL | let c1 : () = c; | -- ^ expected `()`, found closure | | diff --git a/src/test/ui/codegen/issue-64401.rs b/src/test/ui/codegen/issue-64401.rs new file mode 100644 index 0000000000000..53f85c63b5336 --- /dev/null +++ b/src/test/ui/codegen/issue-64401.rs @@ -0,0 +1,51 @@ +// build-pass +// The ICE didn't happen with `cargo check` but `cargo build`. + +use std::marker::PhantomData; + +trait Owned<'a> { + type Reader; +} + +impl<'a> Owned<'a> for () { + type Reader = (); +} + +trait Handler { + fn handle(&self); +} + +struct CtxHandlerWithoutState<M, F> { + message_type: PhantomData<M>, + _function: F, +} + +impl<M, F> CtxHandlerWithoutState<M, F> { + pub fn new(_function: F) -> Self { + Self { + message_type: PhantomData, + _function, + } + } +} + +impl<'a, M, F> Handler for CtxHandlerWithoutState<M, F> +where + F: Fn(<M as Owned<'a>>::Reader), + M: Owned<'a>, +{ + fn handle(&self) {} +} + +fn e_to_i<M: for<'a> Owned<'a>>(_: <M as Owned<'_>>::Reader) {} + +fn send_external_to_internal<M>() +where + M: for<'a> Owned<'a>, +{ + let _: Box<dyn Handler> = Box::new(CtxHandlerWithoutState::<M, _>::new(e_to_i::<M>)); +} + +fn main() { + send_external_to_internal::<()>() +} diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr index f0109f22a2bc1..9d614e610ad86 100644 --- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -32,7 +32,7 @@ LL | let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>; | ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | = note: expected struct `Box<dyn Fn(i32) -> u8>` - found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>` + found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:22]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:14:13 @@ -86,7 +86,7 @@ LL | let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; | ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | = note: expected reference `&dyn Fn(i32) -> u8` - found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:29]` + found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:19]` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:22:13 @@ -122,7 +122,7 @@ LL | let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>; | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | = note: expected struct `Box<dyn Fn(i32) -> u8>` - found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>` + found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:25]>` error: aborting due to 14 previous errors diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr index 3350d1efb5318..980da53603432 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr +++ b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast to the object type `dyn std::error::Error` + = note: required for the cast from `()` to the object type `dyn std::error::Error` error[E0277]: the trait bound `(): std::error::Error` is not satisfied --> $DIR/coerce-issue-49593-box-never-windows.rs:23:49 @@ -12,7 +12,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast to the object type `(dyn std::error::Error + 'static)` + = note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)` error: aborting due to 2 previous errors diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr index fcd2d7f78ff75..322681b97bccb 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast to the object type `dyn std::error::Error` + = note: required for the cast from `()` to the object type `dyn std::error::Error` error[E0277]: the trait bound `(): std::error::Error` is not satisfied --> $DIR/coerce-issue-49593-box-never.rs:23:49 @@ -12,7 +12,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast to the object type `(dyn std::error::Error + 'static)` + = note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)` error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index 912891480790e..c364c707ff9ea 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -1,3 +1,15 @@ +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 + | +LL | impl !Marker1 for dyn Object + Marker2 { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` + +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` + --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1 + | +LL | impl !Marker2 for dyn Object + Marker2 { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1 | @@ -21,18 +33,6 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i LL | impl !Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1 - | -LL | impl !Marker1 for dyn Object + Marker2 { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` - -error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1 - | -LL | impl !Marker2 for dyn Object + Marker2 { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` - error: aborting due to 5 previous errors Some errors have detailed explanations: E0117, E0321, E0371. diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 056198374a4cc..b80429794f92c 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -1,3 +1,15 @@ +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1 + | +LL | impl Marker1 for dyn Object + Marker2 { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` + +error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` + --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1 + | +LL | impl Marker2 for dyn Object + Marker2 { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1 | @@ -21,18 +33,6 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i LL | unsafe impl Send for dyn Object + Marker2 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1 - | -LL | impl Marker1 for dyn Object + Marker2 { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1` - -error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2` - --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1 - | -LL | impl Marker2 for dyn Object + Marker2 { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2` - error: aborting due to 5 previous errors Some errors have detailed explanations: E0117, E0321, E0371. diff --git a/src/test/ui/coherence/coherence-impls-copy.stderr b/src/test/ui/coherence/coherence-impls-copy.stderr index b3ca354c633aa..86356af256433 100644 --- a/src/test/ui/coherence/coherence-impls-copy.stderr +++ b/src/test/ui/coherence/coherence-impls-copy.stderr @@ -9,49 +9,49 @@ LL | impl Copy for i32 {} | = note: define and implement a trait or new type instead +error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync` + --> $DIR/coherence-impls-copy.rs:28:1 + | +LL | impl Copy for &'static NotSync {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl<T> Copy for &T + where T: ?Sized; + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-copy.rs:25:1 + --> $DIR/coherence-impls-copy.rs:33:1 | -LL | impl Copy for (MyType, MyType) {} - | ^^^^^^^^^^^^^^---------------- +LL | impl Copy for &'static [NotSync] {} + | ^^^^^^^^^^^^^^------------------ | | | - | | this is not defined in the current crate because tuples are always foreign + | | this is not defined in the current crate because slices are always foreign | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-copy.rs:30:1 + --> $DIR/coherence-impls-copy.rs:25:1 | -LL | impl Copy for [MyType] {} - | ^^^^^^^^^^^^^^-------- +LL | impl Copy for (MyType, MyType) {} + | ^^^^^^^^^^^^^^---------------- | | | - | | this is not defined in the current crate because slices are always foreign + | | this is not defined in the current crate because tuples are always foreign | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-copy.rs:33:1 + --> $DIR/coherence-impls-copy.rs:30:1 | -LL | impl Copy for &'static [NotSync] {} - | ^^^^^^^^^^^^^^------------------ +LL | impl Copy for [MyType] {} + | ^^^^^^^^^^^^^^-------- | | | | | this is not defined in the current crate because slices are always foreign | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead -error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync` - --> $DIR/coherence-impls-copy.rs:28:1 - | -LL | impl Copy for &'static NotSync {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: conflicting implementation in crate `core`: - - impl<T> Copy for &T - where T: ?Sized; - error[E0206]: the trait `Copy` may not be implemented for this type --> $DIR/coherence-impls-copy.rs:21:15 | diff --git a/src/test/ui/coherence/coherence-impls-send.stderr b/src/test/ui/coherence/coherence-impls-send.stderr index dd1fd1b0dce24..e1071846e146e 100644 --- a/src/test/ui/coherence/coherence-impls-send.stderr +++ b/src/test/ui/coherence/coherence-impls-send.stderr @@ -1,3 +1,14 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence-impls-send.rs:25:1 + | +LL | unsafe impl Send for &'static [NotSync] {} + | ^^^^^^^^^^^^^^^^^^^^^------------------ + | | | + | | this is not defined in the current crate because slices are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/coherence-impls-send.rs:16:1 | @@ -26,17 +37,6 @@ LL | unsafe impl Send for [MyType] {} | = note: define and implement a trait or new type instead -error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-send.rs:25:1 - | -LL | unsafe impl Send for &'static [NotSync] {} - | ^^^^^^^^^^^^^^^^^^^^^------------------ - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate - | - = note: define and implement a trait or new type instead - error: aborting due to 4 previous errors Some errors have detailed explanations: E0117, E0321. diff --git a/src/test/ui/coherence/coherence-impls-sized.stderr b/src/test/ui/coherence/coherence-impls-sized.stderr index e1e4acd4cd82d..17a7544521de5 100644 --- a/src/test/ui/coherence/coherence-impls-sized.stderr +++ b/src/test/ui/coherence/coherence-impls-sized.stderr @@ -1,36 +1,3 @@ -error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-sized.rs:20:1 - | -LL | impl Sized for (MyType, MyType) {} - | ^^^^^^^^^^^^^^^---------------- - | | | - | | this is not defined in the current crate because tuples are always foreign - | impl doesn't use only types from inside the current crate - | - = note: define and implement a trait or new type instead - -error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-sized.rs:27:1 - | -LL | impl Sized for [MyType] {} - | ^^^^^^^^^^^^^^^-------- - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate - | - = note: define and implement a trait or new type instead - -error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence-impls-sized.rs:31:1 - | -LL | impl Sized for &'static [NotSync] {} - | ^^^^^^^^^^^^^^^------------------ - | | | - | | this is not defined in the current crate because slices are always foreign - | impl doesn't use only types from inside the current crate - | - = note: define and implement a trait or new type instead - error[E0322]: explicit impls for the `Sized` trait are not permitted --> $DIR/coherence-impls-sized.rs:14:1 | @@ -49,6 +16,17 @@ error[E0322]: explicit impls for the `Sized` trait are not permitted LL | impl Sized for (MyType, MyType) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence-impls-sized.rs:20:1 + | +LL | impl Sized for (MyType, MyType) {} + | ^^^^^^^^^^^^^^^---------------- + | | | + | | this is not defined in the current crate because tuples are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + error[E0322]: explicit impls for the `Sized` trait are not permitted --> $DIR/coherence-impls-sized.rs:24:1 | @@ -61,12 +39,34 @@ error[E0322]: explicit impls for the `Sized` trait are not permitted LL | impl Sized for [MyType] {} | ^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence-impls-sized.rs:27:1 + | +LL | impl Sized for [MyType] {} + | ^^^^^^^^^^^^^^^-------- + | | | + | | this is not defined in the current crate because slices are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + error[E0322]: explicit impls for the `Sized` trait are not permitted --> $DIR/coherence-impls-sized.rs:31:1 | LL | impl Sized for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence-impls-sized.rs:31:1 + | +LL | impl Sized for &'static [NotSync] {} + | ^^^^^^^^^^^^^^^------------------ + | | | + | | this is not defined in the current crate because slices are always foreign + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + error: aborting due to 9 previous errors Some errors have detailed explanations: E0117, E0322. diff --git a/src/test/ui/coherence/coherence-overlap-downstream.stderr b/src/test/ui/coherence/coherence-overlap-downstream.stderr index 9ab099489d9e5..7f373e595a35f 100644 --- a/src/test/ui/coherence/coherence-overlap-downstream.stderr +++ b/src/test/ui/coherence/coherence-overlap-downstream.stderr @@ -10,7 +10,7 @@ error[E0119]: conflicting implementations of trait `Foo<_>` for type `i32` --> $DIR/coherence-overlap-downstream.rs:14:1 | LL | impl<X, T> Foo<X> for T where T: Bar<X> {} - | --------------------------------------- first implementation here + | ----------------------- first implementation here LL | impl<X> Foo<X> for i32 {} | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | diff --git a/src/test/ui/coherence/coherence-overlap-trait-alias.stderr b/src/test/ui/coherence/coherence-overlap-trait-alias.stderr index 421c86ee51a52..e324c1e799f9e 100644 --- a/src/test/ui/coherence/coherence-overlap-trait-alias.stderr +++ b/src/test/ui/coherence/coherence-overlap-trait-alias.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `u32: C` --> $DIR/coherence-overlap-trait-alias.rs:15:6 | LL | impl C for u32 {} - | ^ cannot infer type for type `u32` + | ^ | note: multiple `impl`s satisfying `u32: C` found --> $DIR/coherence-overlap-trait-alias.rs:14:1 diff --git a/src/test/ui/coherence/coherence-overlap-upstream.stderr b/src/test/ui/coherence/coherence-overlap-upstream.stderr index 8272c88758607..f6145c1883a09 100644 --- a/src/test/ui/coherence/coherence-overlap-upstream.stderr +++ b/src/test/ui/coherence/coherence-overlap-upstream.stderr @@ -2,7 +2,7 @@ error[E0119]: conflicting implementations of trait `Foo` for type `i16` --> $DIR/coherence-overlap-upstream.rs:13:1 | LL | impl<T> Foo for T where T: Remote {} - | --------------------------------- first implementation here + | ----------------- first implementation here LL | impl Foo for i16 {} | ^^^^^^^^^^^^^^^^ conflicting implementation for `i16` | diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr index 8e7d4589e6140..b1ee0795b2eb3 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr @@ -8,7 +8,6 @@ LL | impl<A:Iterator> Foo<A::Item> for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions - = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.stderr b/src/test/ui/coherence/coherence-wasm-bindgen.stderr index 432646e5321eb..aa74e2315392d 100644 --- a/src/test/ui/coherence/coherence-wasm-bindgen.stderr +++ b/src/test/ui/coherence/coherence-wasm-bindgen.stderr @@ -1,22 +1,11 @@ error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _` --> $DIR/coherence-wasm-bindgen.rs:28:1 | -LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b) -LL | | where -LL | | A: FromWasmAbi, -LL | | R: ReturnWasmAbi, -LL | | { -LL | | } - | |_- first implementation here +LL | impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b) + | ------------------------------------------------------------ first implementation here ... -LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b) -LL | | where -LL | | A: RefFromWasmAbi, -LL | | R: ReturnWasmAbi, -... | -LL | | -LL | | } - | |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _` +LL | impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _` | note: the lint level is defined here --> $DIR/coherence-wasm-bindgen.rs:10:9 diff --git a/src/test/ui/coherence/coherence-with-closure.stderr b/src/test/ui/coherence/coherence-with-closure.stderr index 20b986cee6913..d2ca63fa14691 100644 --- a/src/test/ui/coherence/coherence-with-closure.stderr +++ b/src/test/ui/coherence/coherence-with-closure.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>` + --> $DIR/coherence-with-closure.rs:12:1 + | +LL | impl Trait for Wrapper<OpaqueClosure> {} + | ------------------------------------- first implementation here +LL | +LL | impl<T: Sync> Trait for Wrapper<T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>` + error: cannot implement trait on type alias impl trait --> $DIR/coherence-with-closure.rs:10:24 | @@ -10,15 +19,6 @@ note: type alias impl trait defined here LL | type OpaqueClosure = impl Sized; | ^^^^^^^^^^ -error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>` - --> $DIR/coherence-with-closure.rs:12:1 - | -LL | impl Trait for Wrapper<OpaqueClosure> {} - | ------------------------------------- first implementation here -LL | -LL | impl<T: Sync> Trait for Wrapper<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>` - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-with-generator.stderr b/src/test/ui/coherence/coherence-with-generator.stderr index 249ad3cb9ec7f..804bc1c3a6dd4 100644 --- a/src/test/ui/coherence/coherence-with-generator.stderr +++ b/src/test/ui/coherence/coherence-with-generator.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>` + --> $DIR/coherence-with-generator.rs:16:1 + | +LL | impl Trait for Wrapper<OpaqueGenerator> {} + | --------------------------------------- first implementation here +LL | +LL | impl<T: Sync> Trait for Wrapper<T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>` + error: cannot implement trait on type alias impl trait --> $DIR/coherence-with-generator.rs:14:24 | @@ -10,15 +19,6 @@ note: type alias impl trait defined here LL | type OpaqueGenerator = impl Sized; | ^^^^^^^^^^ -error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>` - --> $DIR/coherence-with-generator.rs:16:1 - | -LL | impl Trait for Wrapper<OpaqueGenerator> {} - | --------------------------------------- first implementation here -LL | -LL | impl<T: Sync> Trait for Wrapper<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>` - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs new file mode 100644 index 0000000000000..5b11c78ab2605 --- /dev/null +++ b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs @@ -0,0 +1,19 @@ +struct S; + +impl From<()> for S { + fn from(x: ()) -> Self { + S + } +} + +impl<I> From<I> for S +//~^ ERROR conflicting implementations of trait +where + I: Iterator<Item = ()>, +{ + fn from(x: I) -> Self { + S + } +} + +fn main() {} diff --git a/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr new file mode 100644 index 0000000000000..038a0199a8f27 --- /dev/null +++ b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `std::convert::From<()>` for type `S` + --> $DIR/inter-crate-ambiguity-causes-notes.rs:9:1 + | +LL | impl From<()> for S { + | ------------------- first implementation here +... +LL | impl<I> From<I> for S + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S` + | + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/conflicting-repr-hints.stderr b/src/test/ui/conflicting-repr-hints.stderr index 0f32fc0481bc6..0c7c50d67300c 100644 --- a/src/test/ui/conflicting-repr-hints.stderr +++ b/src/test/ui/conflicting-repr-hints.stderr @@ -21,72 +21,61 @@ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:29:1 | LL | struct F(i32); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:33:1 | LL | struct G(i32); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:37:1 | LL | struct H(i32); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error[E0634]: type has conflicting packed representation hints --> $DIR/conflicting-repr-hints.rs:40:1 | LL | struct I(i32); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error[E0634]: type has conflicting packed representation hints --> $DIR/conflicting-repr-hints.rs:44:1 | LL | struct J(i32); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:50:1 | -LL | / union X { -LL | | -LL | | i: i32, -LL | | } - | |_^ +LL | union X { + | ^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:57:1 | -LL | / union Y { -LL | | -LL | | i: i32, -LL | | } - | |_^ +LL | union Y { + | ^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:64:1 | -LL | / union Z { -LL | | -LL | | i: i32, -LL | | } - | |_^ +LL | union Z { + | ^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:70:1 | LL | pub struct S(u16); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0587]: type has conflicting packed and align representation hints --> $DIR/conflicting-repr-hints.rs:73:1 | -LL | / pub union U { -LL | | u: u16 -LL | | } - | |_^ +LL | pub union U { + | ^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr index 2f67c11ad1f5d..1c9a6847ceb4f 100644 --- a/src/test/ui/confuse-field-and-method/issue-18343.stderr +++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc --> $DIR/issue-18343.rs:7:7 | LL | struct Obj<F> where F: FnMut() -> u32 { - | ------------------------------------- method `closure` not found for this + | ------------- method `closure` not found for this struct ... LL | o.closure(); | ^^^^^^^ field, not a method diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index a37e132d36429..440fbb27c0040 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc --> $DIR/issue-2392.rs:36:15 | LL | struct Obj<F> where F: FnOnce() -> u32 { - | -------------------------------------- method `closure` not found for this + | ------------- method `closure` not found for this struct ... LL | o_closure.closure(); | ^^^^^^^ field, not a method @@ -16,7 +16,7 @@ error[E0599]: no method named `not_closure` found for struct `Obj` in the curren --> $DIR/issue-2392.rs:38:15 | LL | struct Obj<F> where F: FnOnce() -> u32 { - | -------------------------------------- method `not_closure` not found for this + | ------------- method `not_closure` not found for this struct ... LL | o_closure.not_closure(); | ^^^^^^^^^^^-- help: remove the arguments @@ -27,7 +27,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc --> $DIR/issue-2392.rs:42:12 | LL | struct Obj<F> where F: FnOnce() -> u32 { - | -------------------------------------- method `closure` not found for this + | ------------- method `closure` not found for this struct ... LL | o_func.closure(); | ^^^^^^^ field, not a method @@ -41,7 +41,7 @@ error[E0599]: no method named `boxed_closure` found for struct `BoxedObj` in the --> $DIR/issue-2392.rs:45:14 | LL | struct BoxedObj { - | --------------- method `boxed_closure` not found for this + | --------------- method `boxed_closure` not found for this struct ... LL | boxed_fn.boxed_closure(); | ^^^^^^^^^^^^^ field, not a method @@ -55,7 +55,7 @@ error[E0599]: no method named `boxed_closure` found for struct `BoxedObj` in the --> $DIR/issue-2392.rs:48:19 | LL | struct BoxedObj { - | --------------- method `boxed_closure` not found for this + | --------------- method `boxed_closure` not found for this struct ... LL | boxed_closure.boxed_closure(); | ^^^^^^^^^^^^^ field, not a method @@ -69,7 +69,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc --> $DIR/issue-2392.rs:53:12 | LL | struct Obj<F> where F: FnOnce() -> u32 { - | -------------------------------------- method `closure` not found for this + | ------------- method `closure` not found for this struct ... LL | w.wrap.closure(); | ^^^^^^^ field, not a method @@ -83,7 +83,7 @@ error[E0599]: no method named `not_closure` found for struct `Obj` in the curren --> $DIR/issue-2392.rs:55:12 | LL | struct Obj<F> where F: FnOnce() -> u32 { - | -------------------------------------- method `not_closure` not found for this + | ------------- method `not_closure` not found for this struct ... LL | w.wrap.not_closure(); | ^^^^^^^^^^^-- help: remove the arguments @@ -94,7 +94,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc --> $DIR/issue-2392.rs:58:24 | LL | struct Obj<F> where F: FnOnce() -> u32 { - | -------------------------------------- method `closure` not found for this + | ------------- method `closure` not found for this struct ... LL | check_expression().closure(); | ^^^^^^^ field, not a method @@ -108,7 +108,7 @@ error[E0599]: no method named `f1` found for struct `FuncContainer` in the curre --> $DIR/issue-2392.rs:64:31 | LL | struct FuncContainer { - | -------------------- method `f1` not found for this + | -------------------- method `f1` not found for this struct ... LL | (*self.container).f1(1); | ^^ field, not a method @@ -122,7 +122,7 @@ error[E0599]: no method named `f2` found for struct `FuncContainer` in the curre --> $DIR/issue-2392.rs:65:31 | LL | struct FuncContainer { - | -------------------- method `f2` not found for this + | -------------------- method `f2` not found for this struct ... LL | (*self.container).f2(1); | ^^ field, not a method @@ -136,7 +136,7 @@ error[E0599]: no method named `f3` found for struct `FuncContainer` in the curre --> $DIR/issue-2392.rs:66:31 | LL | struct FuncContainer { - | -------------------- method `f3` not found for this + | -------------------- method `f3` not found for this struct ... LL | (*self.container).f3(1); | ^^ field, not a method diff --git a/src/test/ui/confuse-field-and-method/issue-32128.stderr b/src/test/ui/confuse-field-and-method/issue-32128.stderr index 50c6fe1e83308..4b96bce8d2e82 100644 --- a/src/test/ui/confuse-field-and-method/issue-32128.stderr +++ b/src/test/ui/confuse-field-and-method/issue-32128.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `example` found for struct `Example` in the curren --> $DIR/issue-32128.rs:12:10 | LL | struct Example { - | -------------- method `example` not found for this + | -------------- method `example` not found for this struct ... LL | demo.example(1); | ^^^^^^^ field, not a method diff --git a/src/test/ui/confuse-field-and-method/issue-33784.stderr b/src/test/ui/confuse-field-and-method/issue-33784.stderr index 7c2e6b015330f..34debb6831734 100644 --- a/src/test/ui/confuse-field-and-method/issue-33784.stderr +++ b/src/test/ui/confuse-field-and-method/issue-33784.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope +error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope --> $DIR/issue-33784.rs:27:7 | LL | p.closure(); @@ -9,7 +9,7 @@ help: to call the function stored in `closure`, surround the field access with p LL | (p.closure)(); | + + -error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope +error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope --> $DIR/issue-33784.rs:29:7 | LL | q.fn_ptr(); diff --git a/src/test/ui/confuse-field-and-method/private-field.stderr b/src/test/ui/confuse-field-and-method/private-field.stderr index fd98a864742ee..783378f8db58d 100644 --- a/src/test/ui/confuse-field-and-method/private-field.stderr +++ b/src/test/ui/confuse-field-and-method/private-field.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `dog_age` found for struct `Dog` in the current sc --> $DIR/private-field.rs:16:23 | LL | pub struct Dog { - | -------------- method `dog_age` not found for this + | -------------- method `dog_age` not found for this struct ... LL | let dog_age = dog.dog_age(); | ^^^^^^^ private field, not a method diff --git a/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr b/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr index dbbdb2a0ce331..8672e79b3e8c8 100644 --- a/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr +++ b/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr @@ -22,30 +22,6 @@ 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 - --> $DIR/const-arg-in-const-arg.rs:30:23 - | -LL | let _ = [0; faz::<'a>(&())]; - | ^^ - | -note: the late bound lifetime parameter is introduced here - --> $DIR/const-arg-in-const-arg.rs:8:14 - | -LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } - | ^^ - -error: 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>(&())]; - | ^^ - | -note: the late bound lifetime parameter is introduced here - --> $DIR/const-arg-in-const-arg.rs:8:14 - | -LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } - | ^^ - error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present --> $DIR/const-arg-in-const-arg.rs:41:24 | @@ -118,6 +94,30 @@ 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 + --> $DIR/const-arg-in-const-arg.rs:30:23 + | +LL | let _ = [0; faz::<'a>(&())]; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/const-arg-in-const-arg.rs:8:14 + | +LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } + | ^^ + +error: 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>(&())]; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/const-arg-in-const-arg.rs:8:14 + | +LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } + | ^^ + error: unconstrained generic constant --> $DIR/const-arg-in-const-arg.rs:47:19 | diff --git a/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr b/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr index 6ca9a2a48592c..f1353aa99437d 100644 --- a/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -241,21 +241,21 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:27:23 + --> $DIR/const-arg-in-const-arg.rs:38:24 | -LL | let _ = [0; bar::<N>()]; - | ^ +LL | let _: Foo<{ bar::<N>() }>; + | ^ | help: if this generic argument was intended as a const parameter, surround it with braces | -LL | let _ = [0; bar::<{ N }>()]; - | + + +LL | let _: Foo<{ bar::<{ N }>() }>; + | + + error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:30:23 + --> $DIR/const-arg-in-const-arg.rs:41:24 | -LL | let _ = [0; faz::<'a>(&())]; - | ^^ +LL | let _: Foo<{ faz::<'a>(&()) }>; + | ^^ | note: the late bound lifetime parameter is introduced here --> $DIR/const-arg-in-const-arg.rs:8:14 @@ -264,10 +264,10 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:33:23 + --> $DIR/const-arg-in-const-arg.rs:44:24 | -LL | let _ = [0; faz::<'b>(&())]; - | ^^ +LL | let _: Foo<{ faz::<'b>(&()) }>; + | ^^ | note: the late bound lifetime parameter is introduced here --> $DIR/const-arg-in-const-arg.rs:8:14 @@ -275,22 +275,30 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ +error: constant expression depends on a generic parameter + --> $DIR/const-arg-in-const-arg.rs:25:17 + | +LL | let _ = [0; foo::<T>()]; + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:38:24 + --> $DIR/const-arg-in-const-arg.rs:27:23 | -LL | let _: Foo<{ bar::<N>() }>; - | ^ +LL | let _ = [0; bar::<N>()]; + | ^ | help: if this generic argument was intended as a const parameter, surround it with braces | -LL | let _: Foo<{ bar::<{ N }>() }>; - | + + +LL | let _ = [0; bar::<{ N }>()]; + | + + error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:41:24 + --> $DIR/const-arg-in-const-arg.rs:30:23 | -LL | let _: Foo<{ faz::<'a>(&()) }>; - | ^^ +LL | let _ = [0; faz::<'a>(&())]; + | ^^ | note: the late bound lifetime parameter is introduced here --> $DIR/const-arg-in-const-arg.rs:8:14 @@ -299,10 +307,10 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:44:24 + --> $DIR/const-arg-in-const-arg.rs:33:23 | -LL | let _: Foo<{ faz::<'b>(&()) }>; - | ^^ +LL | let _ = [0; faz::<'b>(&())]; + | ^^ | note: the late bound lifetime parameter is introduced here --> $DIR/const-arg-in-const-arg.rs:8:14 @@ -310,14 +318,6 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error: constant expression depends on a generic parameter - --> $DIR/const-arg-in-const-arg.rs:25:17 - | -LL | let _ = [0; foo::<T>()]; - | ^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - error[E0747]: unresolved item provided when a constant was expected --> $DIR/const-arg-in-const-arg.rs:49:27 | diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs b/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs index bb5a2f1766f1b..e64adacac9fd2 100644 --- a/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs +++ b/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs @@ -1,6 +1,5 @@ struct X<const N: usize = { - let s: &'static str; s.len() - //~^ ERROR borrow of possibly-uninitialized variable + let s: &'static str; s.len() //~ ERROR E0381 }>; fn main() {} diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr index 6c25019b0ceb3..c62f1d1d23061 100644 --- a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr +++ b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr @@ -1,8 +1,10 @@ -error[E0381]: borrow of possibly-uninitialized variable: `s` +error[E0381]: used binding `s` isn't initialized --> $DIR/const-generic-default-wont-borrowck.rs:2:26 | LL | let s: &'static str; s.len() - | ^^^^^^^ use of possibly-uninitialized `*s` + | - ^^^^^^^ `*s` used here but it isn't initialized + | | + | binding declared here but left uninitialized error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr index 48d85e7ff64ec..4bba42c7782e3 100644 --- a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr +++ b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr @@ -46,15 +46,6 @@ LL | impl<const N: &u8> A<N> { = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error: `&'static u8` is forbidden as the type of a const generic parameter - --> $DIR/const-param-elided-lifetime.rs:17:21 - | -LL | fn foo<const M: &u8>(&self) {} - | ^^^ - | - = note: the only supported types are integers, `bool` and `char` - = help: more complex types are supported with `#![feature(adt_const_params)]` - error: `&'static u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:22:15 | @@ -73,6 +64,15 @@ LL | fn bar<const N: &u8>() {} = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` +error: `&'static u8` is forbidden as the type of a const generic parameter + --> $DIR/const-param-elided-lifetime.rs:17:21 + | +LL | fn foo<const M: &u8>(&self) {} + | ^^^ + | + = 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 10 previous errors For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr index 60dc96f675a8b..da85b2059f0a3 100644 --- a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr +++ b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr @@ -7,7 +7,7 @@ LL | foo(&10_u32); | required by a bound introduced by this call | = help: the trait `Trait<2_u8>` is implemented for `u32` - = note: required for the cast to the object type `dyn Trait` + = note: required for the cast from `u32` to the object type `dyn Trait` error[E0277]: the trait bound `bool: Traitor<{_: u8}>` is not satisfied --> $DIR/trait_objects_fail.rs:28:9 @@ -18,7 +18,7 @@ LL | bar(&true); | required by a bound introduced by this call | = help: the trait `Traitor<2_u8, 3_u8>` is implemented for `bool` - = note: required for the cast to the object type `dyn Traitor<{_: u8}>` + = note: required for the cast from `bool` to the object type `dyn Traitor<{_: u8}>` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/float-generic.adt_const_params.stderr b/src/test/ui/const-generics/float-generic.adt_const_params.stderr new file mode 100644 index 0000000000000..fef5ef0d1facf --- /dev/null +++ b/src/test/ui/const-generics/float-generic.adt_const_params.stderr @@ -0,0 +1,11 @@ +error[E0741]: `f32` is forbidden as the type of a const generic parameter + --> $DIR/float-generic.rs:5:17 + | +LL | fn foo<const F: f32>() {} + | ^^^ + | + = note: floats do not derive `Eq` or `Ord`, which are required for const parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/float-generic.rs b/src/test/ui/const-generics/float-generic.rs new file mode 100644 index 0000000000000..b72059b5b1c6a --- /dev/null +++ b/src/test/ui/const-generics/float-generic.rs @@ -0,0 +1,12 @@ +// revisions: simple adt_const_params +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] + +fn foo<const F: f32>() {} +//~^ ERROR `f32` is forbidden as the type of a const generic parameter + +const C: f32 = 1.0; + +fn main() { + foo::<C>(); +} diff --git a/src/test/ui/const-generics/float-generic.simple.stderr b/src/test/ui/const-generics/float-generic.simple.stderr new file mode 100644 index 0000000000000..89ca36b0f6314 --- /dev/null +++ b/src/test/ui/const-generics/float-generic.simple.stderr @@ -0,0 +1,11 @@ +error: `f32` is forbidden as the type of a const generic parameter + --> $DIR/float-generic.rs:5:17 + | +LL | fn foo<const F: f32>() {} + | ^^^ + | + = 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 previous error + diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr index 463605e2431d6..688db695fa848 100644 --- a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -2,7 +2,7 @@ error[E0283]: type annotations needed for `Mask<_, LANES>` --> $DIR/issue-91614.rs:6:9 | LL | let y = Mask::<_, _>::splat(false); - | ^ + | ^ ------------------- type must be known at this point | = note: cannot satisfy `_: MaskElement` note: required by a bound in `Mask::<T, LANES>::splat` diff --git a/src/test/ui/const-generics/generic_const_exprs/eval-privacy.stderr b/src/test/ui/const-generics/generic_const_exprs/eval-privacy.stderr index c6b0ce931450d..2d9de8805bb55 100644 --- a/src/test/ui/const-generics/generic_const_exprs/eval-privacy.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/eval-privacy.stderr @@ -2,7 +2,7 @@ error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface --> $DIR/eval-privacy.rs:16:5 | LL | type AssocTy = Const<{ my_const_fn(U) }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^ can't leak private type ... LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr index 0ce7640f68577..77a3b77ad428b 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr @@ -8,7 +8,7 @@ error[E0599]: the function or associated item `foo` exists for struct `Foo<{_: u --> $DIR/issue-69654.rs:17:10 | LL | struct Foo<const N: usize> {} - | -------------------------- function or associated item `foo` not found for this + | -------------------------- function or associated item `foo` not found for this struct ... LL | Foo::foo(); | ^^^ function or associated item cannot be called on `Foo<{_: usize}>` due to unsatisfied trait bounds diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 02dce4f7a97e8..41afaec86b6e4 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -34,19 +34,19 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: const parameters may only be used as standalone arguments, i.e. `J` = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8_u32>: True` --> $DIR/issue-72787.rs:21:26 | LL | IsLessOrEqual<I, 8>: True, - | ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>` + | ^^^^ | = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True` -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual<I, 8_u32>: True` --> $DIR/issue-72787.rs:21:26 | LL | IsLessOrEqual<I, 8>: True, - | ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>` + | ^^^^ | = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True` diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs b/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs index 77ad57f0640fa..c651bf1c8de9d 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs @@ -19,8 +19,8 @@ struct S<const I: u32, const J: u32>; impl<const I: u32, const J: u32> S<I, J> where IsLessOrEqual<I, 8>: True, -//[min]~^ Error type annotations needed [E0283] -//[min]~| Error type annotations needed [E0283] +//[min]~^ Error type annotations needed +//[min]~| Error type annotations needed IsLessOrEqual<J, 8>: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, //[min]~^ Error generic parameters may not be used in const operations diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs b/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs new file mode 100644 index 0000000000000..0bcb997d96cde --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs @@ -0,0 +1,8 @@ +fn bug<'a>() +where + [(); { //~ ERROR mismatched types + let _: &'a (); //~ ERROR a non-static lifetime is not allowed in a `const` + }]: +{} + +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr new file mode 100644 index 0000000000000..e7673df0a025c --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr @@ -0,0 +1,22 @@ +error[E0658]: a non-static lifetime is not allowed in a `const` + --> $DIR/issue-74713.rs:4:17 + | +LL | let _: &'a (); + | ^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable + +error[E0308]: mismatched types + --> $DIR/issue-74713.rs:3:10 + | +LL | [(); { + | __________^ +LL | | let _: &'a (); +LL | | }]: + | |_____^ expected `usize`, found `()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr index 56cb11bacbe6b..1b502642eb7d0 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -15,22 +15,16 @@ LL | [u8; size_of::<T>() + 1]: , error[E0599]: the function or associated item `new` exists for struct `Inline<dyn Debug>`, but its trait bounds were not satisfied --> $DIR/issue-80742.rs:30:36 | -LL | / struct Inline<T> -LL | | where -LL | | [u8; size_of::<T>() + 1]: , -LL | | { -LL | | _phantom: PhantomData<T>, -LL | | buf: [u8; size_of::<T>() + 1], -LL | | } - | |_- function or associated item `new` not found for this +LL | struct Inline<T> + | ---------------- function or associated item `new` not found for this struct ... -LL | let dst = Inline::<dyn Debug>::new(0); - | ^^^ function or associated item cannot be called on `Inline<dyn Debug>` due to unsatisfied trait bounds +LL | let dst = Inline::<dyn Debug>::new(0); + | ^^^ function or associated item cannot be called on `Inline<dyn Debug>` due to unsatisfied trait bounds | ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL | -LL | pub trait Debug { - | --------------- doesn't satisfy `dyn Debug: Sized` +LL | pub trait Debug { + | --------------- doesn't satisfy `dyn Debug: Sized` | = note: the following trait bounds were not satisfied: `dyn Debug: Sized` diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs new file mode 100644 index 0000000000000..67e30232e2fbb --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs @@ -0,0 +1,25 @@ +// check-pass + +#![feature(adt_const_params, generic_const_exprs)] +//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +pub struct Changes<const CHANGES: &'static [&'static str]> +where + [(); CHANGES.len()]:, +{ + changes: [usize; CHANGES.len()], +} + +impl<const CHANGES: &'static [&'static str]> Changes<CHANGES> +where + [(); CHANGES.len()]:, +{ + pub const fn new() -> Self { + Self { + changes: [0; CHANGES.len()], + } + } +} + +pub fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr new file mode 100644 index 0000000000000..b5b2b0e405a26 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr @@ -0,0 +1,19 @@ +warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-1.rs:3:12 + | +LL | #![feature(adt_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-1.rs:3:30 + | +LL | #![feature(adt_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + +warning: 2 warnings emitted + diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs new file mode 100644 index 0000000000000..00568a0894465 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs @@ -0,0 +1,23 @@ +// check-pass + +#![feature(adt_const_params, generic_const_exprs)] +//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +pub struct Changes<const CHANGES: &'static [&'static str]> +where + [(); CHANGES.len()]:, +{ + changes: [usize; CHANGES.len()], +} + +impl<const CHANGES: &'static [&'static str]> Changes<CHANGES> +where + [(); CHANGES.len()]:, +{ + pub fn combine(&mut self, other: &Self) { + for _change in &self.changes {} + } +} + +pub fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr new file mode 100644 index 0000000000000..5dfbd87ccd480 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr @@ -0,0 +1,19 @@ +warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-2.rs:3:12 + | +LL | #![feature(adt_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-2.rs:3:30 + | +LL | #![feature(adt_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + +warning: 2 warnings emitted + diff --git a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs index c6c196db6f2a6..79e9834b54ed2 100644 --- a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs +++ b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs @@ -16,7 +16,6 @@ fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized { } fn main() { - // FIXME(generic_const_exprs): Improve the error message here. use_dyn(&()); //~^ ERROR type annotations needed } diff --git a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr index ce75314ada769..59e9fee1eaf41 100644 --- a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr @@ -1,14 +1,18 @@ -error[E0284]: type annotations needed: cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated` - --> $DIR/object-safety-ok-infer-err.rs:20:5 +error[E0284]: type annotations needed + --> $DIR/object-safety-ok-infer-err.rs:19:5 | LL | use_dyn(&()); - | ^^^^^^^ cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated` + | ^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `use_dyn` | note: required by a bound in `use_dyn` --> $DIR/object-safety-ok-infer-err.rs:14:55 | LL | fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized { | ^^^^^ required by this bound in `use_dyn` +help: consider specifying the generic argument + | +LL | use_dyn::<N>(&()); + | +++++ error: aborting due to previous error diff --git a/src/test/ui/const-generics/ice-68875.rs b/src/test/ui/const-generics/ice-68875.rs new file mode 100644 index 0000000000000..2ef7cfdbe2735 --- /dev/null +++ b/src/test/ui/const-generics/ice-68875.rs @@ -0,0 +1,11 @@ +// check-fail + +struct DataWrapper<'a> { + data: &'a [u8; Self::SIZE], //~ ERROR generic `Self` types are currently not permitted in anonymous constants +} + +impl DataWrapper<'_> { + const SIZE: usize = 14; +} + +pub fn main() {} diff --git a/src/test/ui/const-generics/ice-68875.stderr b/src/test/ui/const-generics/ice-68875.stderr new file mode 100644 index 0000000000000..1db62c57fd438 --- /dev/null +++ b/src/test/ui/const-generics/ice-68875.stderr @@ -0,0 +1,8 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/ice-68875.rs:4:20 + | +LL | data: &'a [u8; Self::SIZE], + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr index aa5cebd873e31..b1b359619dcfa 100644 --- a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr @@ -16,7 +16,7 @@ error[E0599]: no method named `f` found for struct `S` in the current scope --> $DIR/invalid-const-arg-for-type-param.rs:9:7 | LL | struct S; - | --------- method `f` not found for this + | -------- method `f` not found for this struct ... LL | S.f::<0>(); | ^ method not found in `S` diff --git a/src/test/ui/const-generics/issue-46511.rs b/src/test/ui/const-generics/issue-46511.rs new file mode 100644 index 0000000000000..71c50e2f3f7f3 --- /dev/null +++ b/src/test/ui/const-generics/issue-46511.rs @@ -0,0 +1,8 @@ +// check-fail + +struct Foo<'a> //~ ERROR parameter `'a` is never used [E0392] +{ + _a: [u8; std::mem::size_of::<&'a mut u8>()] //~ ERROR a non-static lifetime is not allowed in a `const` +} + +pub fn main() {} diff --git a/src/test/ui/const-generics/issue-46511.stderr b/src/test/ui/const-generics/issue-46511.stderr new file mode 100644 index 0000000000000..b21afa56dcbfc --- /dev/null +++ b/src/test/ui/const-generics/issue-46511.stderr @@ -0,0 +1,21 @@ +error[E0658]: a non-static lifetime is not allowed in a `const` + --> $DIR/issue-46511.rs:5:35 + | +LL | _a: [u8; std::mem::size_of::<&'a mut u8>()] + | ^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable + +error[E0392]: parameter `'a` is never used + --> $DIR/issue-46511.rs:3:12 + | +LL | struct Foo<'a> + | ^^ unused parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0392, E0658. +For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/const-generics/issue-66451.rs b/src/test/ui/const-generics/issue-66451.rs new file mode 100644 index 0000000000000..3335f7d598480 --- /dev/null +++ b/src/test/ui/const-generics/issue-66451.rs @@ -0,0 +1,28 @@ +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +#[derive(Debug, PartialEq, Eq)] +struct Foo { + value: i32, + nested: &'static Bar<i32>, +} + +#[derive(Debug, PartialEq, Eq)] +struct Bar<T>(T); + +struct Test<const F: Foo>; + +fn main() { + let x: Test<{ + Foo { + value: 3, + nested: &Bar(4), + } + }> = Test; + let y: Test<{ + Foo { + value: 3, + nested: &Bar(5), + } + }> = x; //~ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issue-66451.stderr b/src/test/ui/const-generics/issue-66451.stderr new file mode 100644 index 0000000000000..b691eac4f2d0e --- /dev/null +++ b/src/test/ui/const-generics/issue-66451.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/issue-66451.rs:27:10 + | +LL | let y: Test<{ + | ____________- +LL | | Foo { +LL | | value: 3, +LL | | nested: &Bar(5), +LL | | } +LL | | }> = x; + | | - ^ expected `Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }`, found `Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }` + | |______| + | expected due to this + | + = note: expected struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(5_i32) }>` + found struct `Test<Foo { value: 3_i32, nested: &Bar::<i32>(4_i32) }>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issue-70408.rs b/src/test/ui/const-generics/issue-70408.rs new file mode 100644 index 0000000000000..f7557cb492c06 --- /dev/null +++ b/src/test/ui/const-generics/issue-70408.rs @@ -0,0 +1,13 @@ +// build-pass + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] { + BYTES +} + +pub fn main() { + assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]); + assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA"); +} diff --git a/src/test/ui/const-generics/issue-80471.rs b/src/test/ui/const-generics/issue-80471.rs new file mode 100644 index 0000000000000..d0af8a5eaa89f --- /dev/null +++ b/src/test/ui/const-generics/issue-80471.rs @@ -0,0 +1,13 @@ +#![feature(adt_const_params)] +//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +#[derive(PartialEq, Eq)] +enum Nat { + Z, + S(Box<Nat>), +} + +fn foo<const N: Nat>() {} +//~^ ERROR `Box<Nat>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + +fn main() {} diff --git a/src/test/ui/const-generics/issue-80471.stderr b/src/test/ui/const-generics/issue-80471.stderr new file mode 100644 index 0000000000000..dbcc0b7b6007c --- /dev/null +++ b/src/test/ui/const-generics/issue-80471.stderr @@ -0,0 +1,18 @@ +warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-80471.rs:1:12 + | +LL | #![feature(adt_const_params)] + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information + +error[E0741]: `Box<Nat>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-80471.rs:10:17 + | +LL | fn foo<const N: Nat>() {} + | ^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-83765.stderr b/src/test/ui/const-generics/issues/issue-83765.stderr index 98931a3936f52..28ddddf1be62b 100644 --- a/src/test/ui/const-generics/issues/issue-83765.stderr +++ b/src/test/ui/const-generics/issues/issue-83765.stderr @@ -2,7 +2,7 @@ error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, { T::DIM }, --> $DIR/issue-83765.rs:5:5 | LL | const DIM: usize; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | note: ...which requires checking if `TensorDimension` fulfills its obligations... --> $DIR/issue-83765.rs:4:1 diff --git a/src/test/ui/const-generics/issues/issue-97634.rs b/src/test/ui/const-generics/issues/issue-97634.rs new file mode 100644 index 0000000000000..422e8de685645 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-97634.rs @@ -0,0 +1,10 @@ +// build-pass + +pub enum Register<const N: u16> { + Field0 = 40, + Field1, +} + +fn main() { + let _b = Register::<0>::Field1 as u16; +} diff --git a/src/test/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/src/test/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 415a53a56274a..f5396b8381ad7 100644 --- a/src/test/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/src/test/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:38:21 | LL | get_flag::<false, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = 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: 4, align: 4) { @@ -37,7 +37,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:40:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean | = 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: 1, align: 1) { @@ -48,7 +48,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:42:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean | = 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: 1, align: 1) { @@ -59,7 +59,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:42:47 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = 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: 4, align: 4) { diff --git a/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 415a53a56274a..f5396b8381ad7 100644 --- a/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/src/test/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:38:21 | LL | get_flag::<false, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = 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: 4, align: 4) { @@ -37,7 +37,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:40:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean | = 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: 1, align: 1) { @@ -48,7 +48,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:42:14 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x42, but expected a boolean | = 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: 1, align: 1) { @@ -59,7 +59,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/invalid-patterns.rs:42:47 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = 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: 4, align: 4) { diff --git a/src/test/ui/const-generics/overlapping_impls.rs b/src/test/ui/const-generics/overlapping_impls.rs new file mode 100644 index 0000000000000..e599eadd8cf48 --- /dev/null +++ b/src/test/ui/const-generics/overlapping_impls.rs @@ -0,0 +1,36 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![feature(generic_const_exprs)] +use std::marker::PhantomData; + +struct Foo<const I: i32, const J: i32> {} + +const ONE: i32 = 1; +const TWO: i32 = 2; + +impl<const I: i32> Foo<I, ONE> { + pub fn foo() {} +} + +impl<const I: i32> Foo<I, TWO> { + pub fn foo() {} +} + + +pub struct Foo2<const P: Protocol, T> { + _marker: PhantomData<T>, +} + +#[derive(PartialEq, Eq)] +pub enum Protocol { + Variant1, + Variant2, +} + +pub trait Bar {} + +impl<T> Bar for Foo2<{ Protocol::Variant1 }, T> {} +impl<T> Bar for Foo2<{ Protocol::Variant2 }, T> {} + +fn main() {} diff --git a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs index ed81c01bb1726..7a78e0f109ca7 100644 --- a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs +++ b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs @@ -7,5 +7,5 @@ extern crate generics_of_parent_impl_trait; fn main() { // check for `impl Trait<{ const }>` which has a parent of a `DefKind::TyParam` generics_of_parent_impl_trait::foo([()]); - //~^ error: type annotations needed: + //~^ error: type annotations needed } diff --git a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr index 99085711513d8..87ff7babe71c0 100644 --- a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr +++ b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `the constant `foo::{opaque#0}::{constant#0}` can be evaluated` +error[E0284]: type annotations needed --> $DIR/parent_generics_of_encoding_impl_trait.rs:9:5 | LL | generics_of_parent_impl_trait::foo([()]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `foo::{opaque#0}::{constant#0}` can be evaluated` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `foo` | note: required by a bound in `foo` --> $DIR/auxiliary/generics_of_parent_impl_trait.rs:6:48 diff --git a/src/test/ui/const-generics/try_unify_ignore_lifetimes.rs b/src/test/ui/const-generics/try_unify_ignore_lifetimes.rs new file mode 100644 index 0000000000000..2ae0ae70dd977 --- /dev/null +++ b/src/test/ui/const-generics/try_unify_ignore_lifetimes.rs @@ -0,0 +1,33 @@ +// check-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct Num<const N: usize>; + +trait NumT { + const VALUE: usize; +} + +impl<const N: usize> NumT for Num<N> { + const VALUE: usize = N; +} + +struct Foo<'a, N: NumT>(&'a [u32; N::VALUE]) where [(); N::VALUE]:; + +trait Bar { + type Size: NumT; + + fn bar<'a>(foo: &Foo<'a, Self::Size>) where [(); Self::Size::VALUE]: { + todo!(); + } +} + +trait Baz<'a> { + type Size: NumT; + + fn baz(foo: &Foo<'a, Self::Size>) where [(); Self::Size::VALUE]: { + todo!(); + } +} + +fn main() {} diff --git a/src/test/ui/const-ptr/allowed_slices.rs b/src/test/ui/const-ptr/allowed_slices.rs index 645283d8fe5ac..3f19cd4d8046d 100644 --- a/src/test/ui/const-ptr/allowed_slices.rs +++ b/src/test/ui/const-ptr/allowed_slices.rs @@ -1,6 +1,5 @@ // run-pass #![feature( - const_slice_from_raw_parts, slice_from_ptr_range, const_slice_from_ptr_range, pointer_byte_offsets, diff --git a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr index 023d5ea34d871..c2d22ca4917db 100644 --- a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr +++ b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr @@ -4,13 +4,13 @@ error[E0080]: could not evaluate static initializer LL | &*ptr::slice_from_raw_parts(data, len) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | dereferencing pointer failed: null pointer is not a valid pointer + | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:19:34 + ::: $DIR/forbidden_slices.rs:18:34 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34 + | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -18,13 +18,13 @@ error[E0080]: could not evaluate static initializer LL | &*ptr::slice_from_raw_parts(data, len) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | dereferencing pointer failed: null pointer is not a valid pointer + | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:20:33 + ::: $DIR/forbidden_slices.rs:19:33 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33 + | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -35,16 +35,16 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:23:34 + ::: $DIR/forbidden_slices.rs:22:34 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34 + | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:26:1 + --> $DIR/forbidden_slices.rs:25:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes | = 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: 8, align: 4) { @@ -52,10 +52,10 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:28:1 + --> $DIR/forbidden_slices.rs:27:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = 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: 8, align: 4) { @@ -63,10 +63,10 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:30:1 + --> $DIR/forbidden_slices.rs:29:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean | = 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: 8, align: 4) { @@ -74,15 +74,10 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:33:1 + --> $DIR/forbidden_slices.rs:32:1 | -LL | / pub static S7: &[u16] = unsafe { -LL | | -LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1); -LL | | -LL | | from_raw_parts(ptr, 4) -LL | | }; - | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +LL | pub static S7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = 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: 8, align: 4) { @@ -98,10 +93,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:44:5 + ::: $DIR/forbidden_slices.rs:43:5 | LL | from_raw_parts(ptr, 1) - | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5 + | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -109,7 +104,7 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | out-of-bounds offset_from: null pointer is not a valid pointer + | out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -117,10 +112,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:47:34 + ::: $DIR/forbidden_slices.rs:46:34 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34 + | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -136,10 +131,10 @@ LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:48:33 + ::: $DIR/forbidden_slices.rs:47:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33 + | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -149,26 +144,22 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + | out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL ... LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:51:25 + ::: $DIR/forbidden_slices.rs:50:25 | LL | from_ptr_range(ptr..ptr.add(2)) - | ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25 + | ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:53:1 + --> $DIR/forbidden_slices.rs:52:1 | -LL | / pub static R4: &[u8] = unsafe { -LL | | -LL | | let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8; -LL | | from_ptr_range(ptr..ptr.add(1)) -LL | | }; - | |__^ type validation failed at .<deref>[0]: encountered uninitialized bytes +LL | pub static R4: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes | = 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: 8, align: 4) { @@ -176,14 +167,10 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:58:1 + --> $DIR/forbidden_slices.rs:57:1 | -LL | / pub static R5: &[u8] = unsafe { -LL | | -LL | | let ptr = &D3 as *const &u32; -LL | | from_ptr_range(ptr.cast()..ptr.add(1).cast()) -LL | | }; - | |__^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes +LL | pub static R5: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = 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: 8, align: 4) { @@ -191,14 +178,10 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:63:1 + --> $DIR/forbidden_slices.rs:62:1 | -LL | / pub static R6: &[bool] = unsafe { -LL | | -LL | | let ptr = &D0 as *const u32 as *const bool; -LL | | from_ptr_range(ptr..ptr.add(4)) -LL | | }; - | |__^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean +LL | pub static R6: &[bool] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean | = 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: 8, align: 4) { @@ -206,14 +189,10 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:68:1 + --> $DIR/forbidden_slices.rs:67:1 | -LL | / pub static R7: &[u16] = unsafe { -LL | | -LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1); -LL | | from_ptr_range(ptr..ptr.add(4)) -LL | | }; - | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +LL | pub static R7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = 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: 8, align: 4) { @@ -226,16 +205,16 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds + | out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL ... LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:75:25 + ::: $DIR/forbidden_slices.rs:74:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25 + | ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -251,10 +230,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:80:34 + ::: $DIR/forbidden_slices.rs:79:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34 + | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -270,10 +249,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:81:35 + ::: $DIR/forbidden_slices.rs:80:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35 + | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35 error: aborting due to 18 previous errors diff --git a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr index ed89c253d532c..da9df1c63a4cb 100644 --- a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr +++ b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr @@ -4,13 +4,13 @@ error[E0080]: could not evaluate static initializer LL | &*ptr::slice_from_raw_parts(data, len) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | dereferencing pointer failed: null pointer is not a valid pointer + | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:19:34 + ::: $DIR/forbidden_slices.rs:18:34 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34 + | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -18,13 +18,13 @@ error[E0080]: could not evaluate static initializer LL | &*ptr::slice_from_raw_parts(data, len) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | dereferencing pointer failed: null pointer is not a valid pointer + | dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:20:33 + ::: $DIR/forbidden_slices.rs:19:33 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33 + | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -35,16 +35,16 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:23:34 + ::: $DIR/forbidden_slices.rs:22:34 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34 + | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:26:1 + --> $DIR/forbidden_slices.rs:25:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered uninitialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes | = 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: 16, align: 8) { @@ -52,10 +52,10 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:28:1 + --> $DIR/forbidden_slices.rs:27:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = 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: 16, align: 8) { @@ -63,10 +63,10 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:30:1 + --> $DIR/forbidden_slices.rs:29:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean | = 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: 16, align: 8) { @@ -74,15 +74,10 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:33:1 + --> $DIR/forbidden_slices.rs:32:1 | -LL | / pub static S7: &[u16] = unsafe { -LL | | -LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1); -LL | | -LL | | from_raw_parts(ptr, 4) -LL | | }; - | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +LL | pub static S7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = 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: 16, align: 8) { @@ -98,10 +93,10 @@ LL | &*ptr::slice_from_raw_parts(data, len) | dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:44:5 + ::: $DIR/forbidden_slices.rs:43:5 | LL | from_raw_parts(ptr, 1) - | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5 + | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -109,7 +104,7 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | out-of-bounds offset_from: null pointer is not a valid pointer + | out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL @@ -117,10 +112,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:47:34 + ::: $DIR/forbidden_slices.rs:46:34 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34 + | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -136,10 +131,10 @@ LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:48:33 + ::: $DIR/forbidden_slices.rs:47:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; - | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33 + | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -149,26 +144,22 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + | out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL ... LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:51:25 + ::: $DIR/forbidden_slices.rs:50:25 | LL | from_ptr_range(ptr..ptr.add(2)) - | ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25 + | ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25 error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:53:1 + --> $DIR/forbidden_slices.rs:52:1 | -LL | / pub static R4: &[u8] = unsafe { -LL | | -LL | | let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8; -LL | | from_ptr_range(ptr..ptr.add(1)) -LL | | }; - | |__^ type validation failed at .<deref>[0]: encountered uninitialized bytes +LL | pub static R4: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes | = 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: 16, align: 8) { @@ -176,14 +167,10 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:58:1 + --> $DIR/forbidden_slices.rs:57:1 | -LL | / pub static R5: &[u8] = unsafe { -LL | | -LL | | let ptr = &D3 as *const &u32; -LL | | from_ptr_range(ptr.cast()..ptr.add(1).cast()) -LL | | }; - | |__^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes +LL | pub static R5: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = 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: 16, align: 8) { @@ -191,14 +178,10 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:63:1 + --> $DIR/forbidden_slices.rs:62:1 | -LL | / pub static R6: &[bool] = unsafe { -LL | | -LL | | let ptr = &D0 as *const u32 as *const bool; -LL | | from_ptr_range(ptr..ptr.add(4)) -LL | | }; - | |__^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean +LL | pub static R6: &[bool] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean | = 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: 16, align: 8) { @@ -206,14 +189,10 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:68:1 + --> $DIR/forbidden_slices.rs:67:1 | -LL | / pub static R7: &[u16] = unsafe { -LL | | -LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1); -LL | | from_ptr_range(ptr..ptr.add(4)) -LL | | }; - | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +LL | pub static R7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = 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: 16, align: 8) { @@ -226,16 +205,16 @@ error[E0080]: could not evaluate static initializer LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds + | out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL ... LL | unsafe { self.offset(count as isize) } | --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:75:25 + ::: $DIR/forbidden_slices.rs:74:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25 + | ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -251,10 +230,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:80:34 + ::: $DIR/forbidden_slices.rs:79:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; - | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34 + | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34 error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -270,10 +249,10 @@ LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL | - ::: $DIR/forbidden_slices.rs:81:35 + ::: $DIR/forbidden_slices.rs:80:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; - | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35 + | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35 error: aborting due to 18 previous errors diff --git a/src/test/ui/const-ptr/forbidden_slices.rs b/src/test/ui/const-ptr/forbidden_slices.rs index 4465da454687f..e2184911f422c 100644 --- a/src/test/ui/const-ptr/forbidden_slices.rs +++ b/src/test/ui/const-ptr/forbidden_slices.rs @@ -3,7 +3,6 @@ // normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x" // error-pattern: could not evaluate static initializer #![feature( - const_slice_from_raw_parts, slice_from_ptr_range, const_slice_from_ptr_range, pointer_byte_offsets, diff --git a/src/test/ui/consts/assert-type-intrinsics.stderr b/src/test/ui/consts/assert-type-intrinsics.stderr index bb57ee82cc16f..f3b9170d428af 100644 --- a/src/test/ui/consts/assert-type-intrinsics.stderr +++ b/src/test/ui/consts/assert-type-intrinsics.stderr @@ -1,11 +1,10 @@ error: any use of this value will cause an error --> $DIR/assert-type-intrinsics.rs:14:9 | -LL | / const _BAD1: () = unsafe { -LL | | MaybeUninit::<!>::uninit().assume_init(); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` -LL | | }; - | |______- +LL | const _BAD1: () = unsafe { + | --------------- +LL | MaybeUninit::<!>::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -14,11 +13,10 @@ LL | | }; error: any use of this value will cause an error --> $DIR/assert-type-intrinsics.rs:17:9 | -LL | / const _BAD2: () = unsafe { -LL | | intrinsics::assert_uninit_valid::<bool>(); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid -LL | | }; - | |______- +LL | const _BAD2: () = unsafe { + | --------------- +LL | intrinsics::assert_uninit_valid::<bool>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -26,14 +24,52 @@ LL | | }; error: any use of this value will cause an error --> $DIR/assert-type-intrinsics.rs:20:9 | -LL | / const _BAD3: () = unsafe { -LL | | intrinsics::assert_zero_valid::<&'static i32>(); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid -LL | | }; - | |______- +LL | const _BAD3: () = unsafe { + | --------------- +LL | intrinsics::assert_zero_valid::<&'static i32>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 3 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/assert-type-intrinsics.rs:14:9 + | +LL | const _BAD1: () = unsafe { + | --------------- +LL | MaybeUninit::<!>::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/assert-type-intrinsics.rs:17:9 + | +LL | const _BAD2: () = unsafe { + | --------------- +LL | intrinsics::assert_uninit_valid::<bool>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/assert-type-intrinsics.rs:20:9 + | +LL | const _BAD3: () = unsafe { + | --------------- +LL | intrinsics::assert_zero_valid::<&'static i32>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr index 96cb904fa1b19..17cbaef1f06d7 100644 --- a/src/test/ui/consts/assoc_const_generic_impl.stderr +++ b/src/test/ui/consts/assoc_const_generic_impl.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/assoc_const_generic_impl.rs:11:34 | LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()]; - | -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | index out of bounds: the length is 1 but the index is 4 + | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4 | note: the lint level is defined here --> $DIR/assoc_const_generic_impl.rs:3:9 @@ -22,3 +20,18 @@ LL | let () = Self::I_AM_ZERO_SIZED; error: aborting due to previous error; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/assoc_const_generic_impl.rs:11:34 + | +LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()]; + | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 4 + | +note: the lint level is defined here + --> $DIR/assoc_const_generic_impl.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-as-fn.stderr b/src/test/ui/consts/const-as-fn.stderr index b8dd4134b284d..6c51ed89393a5 100644 --- a/src/test/ui/consts/const-as-fn.stderr +++ b/src/test/ui/consts/const-as-fn.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `usize` --> $DIR/const-as-fn.rs:4:5 | LL | const FOO: usize = 0; - | --------------------- `FOO` defined here + | ---------------- `FOO` defined here ... LL | FOO(); | ^^^-- diff --git a/src/test/ui/consts/const-deref-ptr.stderr b/src/test/ui/consts/const-deref-ptr.stderr index 7606afdc4ff6c..22cb6451e874a 100644 --- a/src/test/ui/consts/const-deref-ptr.stderr +++ b/src/test/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef[noalloc] is a dangling pointer (it has no provenance) error: aborting due to previous error diff --git a/src/test/ui/consts/const-enum-cast.rs b/src/test/ui/consts/const-enum-cast.rs index a3255c2f601b3..3996849514412 100644 --- a/src/test/ui/consts/const-enum-cast.rs +++ b/src/test/ui/consts/const-enum-cast.rs @@ -4,6 +4,19 @@ enum A { A1, A2 } enum B { B1=4, B2=2 } +#[allow(dead_code)] +#[repr(align(8))] +enum Aligned { + Zero = 0, + One = 1, +} + +// regression test for https://github.com/rust-lang/rust/issues/96185 +const X: u8 = { + let aligned = Aligned::Zero; + aligned as u8 +}; + pub fn main () { static c1: isize = A::A2 as isize; static c2: isize = B::B2 as isize; @@ -23,4 +36,6 @@ pub fn main () { assert_eq!(c2_2, 4); assert_eq!(a1_2, 0); assert_eq!(a2_2, 4); + + assert_eq!(X, 0); } diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr index 2b3d881738762..1b94aa080dda5 100644 --- a/src/test/ui/consts/const-err-early.stderr +++ b/src/test/ui/consts/const-err-early.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-err-early.rs:3:19 | LL | pub const A: i8 = -i8::MIN; - | ------------------^^^^^^^^- - | | - | attempt to negate `i8::MIN`, which would overflow + | --------------- ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | note: the lint level is defined here --> $DIR/const-err-early.rs:1:9 @@ -18,9 +16,7 @@ error: any use of this value will cause an error --> $DIR/const-err-early.rs:5:19 | LL | pub const B: u8 = 200u8 + 200u8; - | ------------------^^^^^^^^^^^^^- - | | - | attempt to compute `200_u8 + 200_u8`, which would overflow + | --------------- ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -29,9 +25,7 @@ error: any use of this value will cause an error --> $DIR/const-err-early.rs:7:19 | LL | pub const C: u8 = 200u8 * 4; - | ------------------^^^^^^^^^- - | | - | attempt to compute `200_u8 * 4_u8`, which would overflow + | --------------- ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -40,9 +34,7 @@ error: any use of this value will cause an error --> $DIR/const-err-early.rs:9:19 | LL | pub const D: u8 = 42u8 - (42u8 + 1); - | ------------------^^^^^^^^^^^^^^^^^- - | | - | attempt to compute `42_u8 - 43_u8`, which would overflow + | --------------- ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -51,12 +43,85 @@ error: any use of this value will cause an error --> $DIR/const-err-early.rs:11:19 | LL | pub const E: u8 = [5u8][1]; - | ------------------^^^^^^^^- - | | - | index out of bounds: the length is 1 but the index is 1 + | --------------- ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 5 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-early.rs:3:19 + | +LL | pub const A: i8 = -i8::MIN; + | --------------- ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-err-early.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-early.rs:5:19 + | +LL | pub const B: u8 = 200u8 + 200u8; + | --------------- ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-err-early.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-early.rs:7:19 + | +LL | pub const C: u8 = 200u8 * 4; + | --------------- ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-err-early.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-early.rs:9:19 + | +LL | pub const D: u8 = 42u8 - (42u8 + 1); + | --------------- ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-err-early.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-early.rs:11:19 + | +LL | pub const E: u8 = [5u8][1]; + | --------------- ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | +note: the lint level is defined here + --> $DIR/const-err-early.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr index c8172e83d10e2..f179843654e9b 100644 --- a/src/test/ui/consts/const-err-multi.stderr +++ b/src/test/ui/consts/const-err-multi.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-err-multi.rs:3:19 | LL | pub const A: i8 = -i8::MIN; - | ------------------^^^^^^^^- - | | - | attempt to negate `i8::MIN`, which would overflow + | --------------- ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | note: the lint level is defined here --> $DIR/const-err-multi.rs:1:9 @@ -18,9 +16,7 @@ error: any use of this value will cause an error --> $DIR/const-err-multi.rs:6:19 | LL | pub const B: i8 = A; - | ------------------^- - | | - | referenced constant has errors + | --------------- ^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -29,9 +25,7 @@ error: any use of this value will cause an error --> $DIR/const-err-multi.rs:9:19 | LL | pub const C: u8 = A as u8; - | ------------------^------- - | | - | referenced constant has errors + | --------------- ^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -40,12 +34,70 @@ error: any use of this value will cause an error --> $DIR/const-err-multi.rs:12:24 | LL | pub const D: i8 = 50 - A; - | -----------------------^- - | | - | referenced constant has errors + | --------------- ^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 4 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-multi.rs:3:19 + | +LL | pub const A: i8 = -i8::MIN; + | --------------- ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-err-multi.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-multi.rs:6:19 + | +LL | pub const B: i8 = A; + | --------------- ^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/const-err-multi.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-multi.rs:9:19 + | +LL | pub const C: u8 = A as u8; + | --------------- ^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/const-err-multi.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-err-multi.rs:12:24 + | +LL | pub const D: i8 = 50 - A; + | --------------- ^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/const-err-multi.rs:1:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr index 0c963874a8496..e3b0d29c85324 100644 --- a/src/test/ui/consts/const-err.stderr +++ b/src/test/ui/consts/const-err.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/const-err.rs:11:17 | LL | const FOO: u8 = [5u8][1]; - | ----------------^^^^^^^^- - | | - | index out of bounds: the length is 1 but the index is 1 + | ------------- ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | note: the lint level is defined here --> $DIR/const-err.rs:5:9 @@ -29,3 +27,18 @@ LL | black_box((FOO, FOO)); error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const-err.rs:11:17 + | +LL | const FOO: u8 = [5u8][1]; + | ------------- ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | +note: the lint level is defined here + --> $DIR/const-err.rs:5:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-err4.32bit.stderr b/src/test/ui/consts/const-err4.32bit.stderr index 922569f66cf40..a553847833a89 100644 --- a/src/test/ui/consts/const-err4.32bit.stderr +++ b/src/test/ui/consts/const-err4.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-err4.rs:9:11 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/const-err4.64bit.stderr b/src/test/ui/consts/const-err4.64bit.stderr index d7b848e8345a0..66bfc30c3a827 100644 --- a/src/test/ui/consts/const-err4.64bit.stderr +++ b/src/test/ui/consts/const-err4.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-err4.rs:9:11 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index 9dc40030a6ff8..2312e2a45db5b 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/conditional_array_execution.rs:7:19 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ------------------^^^^^--------------------------- - | | - | attempt to compute `5_u32 - 6_u32`, which would overflow + | -------------- ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow | note: the lint level is defined here --> $DIR/conditional_array_execution.rs:3:9 @@ -33,3 +31,34 @@ LL | println!("{}", FOO); error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/conditional_array_execution.rs:7:19 + | +LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; + | -------------- ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/conditional_array_execution.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: erroneous constant used + --> $DIR/conditional_array_execution.rs:12:20 + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/conditional_array_execution.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr index 26728cf541582..cf50c19caa7dd 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr @@ -12,3 +12,18 @@ LL | NEG_NEG_128 => println!("A"), error: aborting due to 2 previous errors +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const-eval-overflow-2.rs:11:25 + | +LL | const NEG_NEG_128: i8 = -NEG_128; + | --------------------- ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow-2.rs:4:36 + | +LL | #![allow(unused_imports, warnings, const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr index 66e86c352d154..dab9a76c7d423 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr @@ -1,12 +1,11 @@ error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:14:6 | -LL | / const VALS_I8: (i8,) = -LL | | ( -LL | | i8::MIN - 1, - | | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I8: (i8,) = + | -------------------- +LL | ( +LL | i8::MIN - 1, + | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow | note: the lint level is defined here --> $DIR/const-eval-overflow2.rs:8:9 @@ -19,12 +18,11 @@ LL | #![deny(const_err)] error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:21:6 | -LL | / const VALS_I16: (i16,) = -LL | | ( -LL | | i16::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I16: (i16,) = + | ---------------------- +LL | ( +LL | i16::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -32,12 +30,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:28:6 | -LL | / const VALS_I32: (i32,) = -LL | | ( -LL | | i32::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I32: (i32,) = + | ---------------------- +LL | ( +LL | i32::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -45,12 +42,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:35:6 | -LL | / const VALS_I64: (i64,) = -LL | | ( -LL | | i64::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I64: (i64,) = + | ---------------------- +LL | ( +LL | i64::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -58,12 +54,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:42:6 | -LL | / const VALS_U8: (u8,) = -LL | | ( -LL | | u8::MIN - 1, - | | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U8: (u8,) = + | -------------------- +LL | ( +LL | u8::MIN - 1, + | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -71,11 +66,10 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:48:6 | -LL | / const VALS_U16: (u16,) = ( -LL | | u16::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U16: (u16,) = ( + | ---------------------- +LL | u16::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -83,11 +77,10 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:54:6 | -LL | / const VALS_U32: (u32,) = ( -LL | | u32::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U32: (u32,) = ( + | ---------------------- +LL | u32::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -95,15 +88,156 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2.rs:61:6 | -LL | / const VALS_U64: (u64,) = -LL | | ( -LL | | u64::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U64: (u64,) = + | ---------------------- +LL | ( +LL | u64::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 8 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:14:6 + | +LL | const VALS_I8: (i8,) = + | -------------------- +LL | ( +LL | i8::MIN - 1, + | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:21:6 + | +LL | const VALS_I16: (i16,) = + | ---------------------- +LL | ( +LL | i16::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:28:6 + | +LL | const VALS_I32: (i32,) = + | ---------------------- +LL | ( +LL | i32::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:35:6 + | +LL | const VALS_I64: (i64,) = + | ---------------------- +LL | ( +LL | i64::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:42:6 + | +LL | const VALS_U8: (u8,) = + | -------------------- +LL | ( +LL | u8::MIN - 1, + | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:48:6 + | +LL | const VALS_U16: (u16,) = ( + | ---------------------- +LL | u16::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:54:6 + | +LL | const VALS_U32: (u32,) = ( + | ---------------------- +LL | u32::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2.rs:61:6 + | +LL | const VALS_U64: (u64,) = + | ---------------------- +LL | ( +LL | u64::MIN - 1, + | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr index 3401ba4776500..5fe9917437e00 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -1,12 +1,11 @@ error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:14:6 | -LL | / const VALS_I8: (i8,) = -LL | | ( -LL | | i8::MAX + 1, - | | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I8: (i8,) = + | -------------------- +LL | ( +LL | i8::MAX + 1, + | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow | note: the lint level is defined here --> $DIR/const-eval-overflow2b.rs:8:9 @@ -19,12 +18,11 @@ LL | #![deny(const_err)] error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:21:6 | -LL | / const VALS_I16: (i16,) = -LL | | ( -LL | | i16::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I16: (i16,) = + | ---------------------- +LL | ( +LL | i16::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -32,12 +30,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:28:6 | -LL | / const VALS_I32: (i32,) = -LL | | ( -LL | | i32::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I32: (i32,) = + | ---------------------- +LL | ( +LL | i32::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -45,12 +42,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:35:6 | -LL | / const VALS_I64: (i64,) = -LL | | ( -LL | | i64::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I64: (i64,) = + | ---------------------- +LL | ( +LL | i64::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -58,12 +54,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:42:6 | -LL | / const VALS_U8: (u8,) = -LL | | ( -LL | | u8::MAX + 1, - | | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U8: (u8,) = + | -------------------- +LL | ( +LL | u8::MAX + 1, + | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -71,11 +66,10 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:48:6 | -LL | / const VALS_U16: (u16,) = ( -LL | | u16::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U16: (u16,) = ( + | ---------------------- +LL | u16::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -83,11 +77,10 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:54:6 | -LL | / const VALS_U32: (u32,) = ( -LL | | u32::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U32: (u32,) = ( + | ---------------------- +LL | u32::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -95,15 +88,156 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2b.rs:61:6 | -LL | / const VALS_U64: (u64,) = -LL | | ( -LL | | u64::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U64: (u64,) = + | ---------------------- +LL | ( +LL | u64::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 8 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:14:6 + | +LL | const VALS_I8: (i8,) = + | -------------------- +LL | ( +LL | i8::MAX + 1, + | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:21:6 + | +LL | const VALS_I16: (i16,) = + | ---------------------- +LL | ( +LL | i16::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:28:6 + | +LL | const VALS_I32: (i32,) = + | ---------------------- +LL | ( +LL | i32::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:35:6 + | +LL | const VALS_I64: (i64,) = + | ---------------------- +LL | ( +LL | i64::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:42:6 + | +LL | const VALS_U8: (u8,) = + | -------------------- +LL | ( +LL | u8::MAX + 1, + | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:48:6 + | +LL | const VALS_U16: (u16,) = ( + | ---------------------- +LL | u16::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:54:6 + | +LL | const VALS_U32: (u32,) = ( + | ---------------------- +LL | u32::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2b.rs:61:6 + | +LL | const VALS_U64: (u64,) = + | ---------------------- +LL | ( +LL | u64::MAX + 1, + | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2b.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr index 93c64090f0eeb..d5f3a0fb1c3f4 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -1,12 +1,11 @@ error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:14:6 | -LL | / const VALS_I8: (i8,) = -LL | | ( -LL | | i8::MIN * 2, - | | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I8: (i8,) = + | -------------------- +LL | ( +LL | i8::MIN * 2, + | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow | note: the lint level is defined here --> $DIR/const-eval-overflow2c.rs:8:9 @@ -19,12 +18,11 @@ LL | #![deny(const_err)] error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:21:6 | -LL | / const VALS_I16: (i16,) = -LL | | ( -LL | | i16::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I16: (i16,) = + | ---------------------- +LL | ( +LL | i16::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -32,12 +30,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:28:6 | -LL | / const VALS_I32: (i32,) = -LL | | ( -LL | | i32::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I32: (i32,) = + | ---------------------- +LL | ( +LL | i32::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -45,12 +42,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:35:6 | -LL | / const VALS_I64: (i64,) = -LL | | ( -LL | | i64::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow -LL | | ); - | |_______- +LL | const VALS_I64: (i64,) = + | ---------------------- +LL | ( +LL | i64::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -58,12 +54,11 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:42:6 | -LL | / const VALS_U8: (u8,) = -LL | | ( -LL | | u8::MAX * 2, - | | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U8: (u8,) = + | -------------------- +LL | ( +LL | u8::MAX * 2, + | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -71,11 +66,10 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:48:6 | -LL | / const VALS_U16: (u16,) = ( -LL | | u16::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U16: (u16,) = ( + | ---------------------- +LL | u16::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -83,11 +77,10 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:54:6 | -LL | / const VALS_U32: (u32,) = ( -LL | | u32::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U32: (u32,) = ( + | ---------------------- +LL | u32::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -95,15 +88,156 @@ LL | | ); error: any use of this value will cause an error --> $DIR/const-eval-overflow2c.rs:61:6 | -LL | / const VALS_U64: (u64,) = -LL | | ( -LL | | u64::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow -LL | | ); - | |_______- +LL | const VALS_U64: (u64,) = + | ---------------------- +LL | ( +LL | u64::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 8 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:14:6 + | +LL | const VALS_I8: (i8,) = + | -------------------- +LL | ( +LL | i8::MIN * 2, + | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:21:6 + | +LL | const VALS_I16: (i16,) = + | ---------------------- +LL | ( +LL | i16::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:28:6 + | +LL | const VALS_I32: (i32,) = + | ---------------------- +LL | ( +LL | i32::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:35:6 + | +LL | const VALS_I64: (i64,) = + | ---------------------- +LL | ( +LL | i64::MIN * 2, + | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:42:6 + | +LL | const VALS_U8: (u8,) = + | -------------------- +LL | ( +LL | u8::MAX * 2, + | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:48:6 + | +LL | const VALS_U16: (u16,) = ( + | ---------------------- +LL | u16::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:54:6 + | +LL | const VALS_U32: (u32,) = ( + | ---------------------- +LL | u32::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-eval-overflow2c.rs:61:6 + | +LL | const VALS_U64: (u64,) = + | ---------------------- +LL | ( +LL | u64::MAX * 2, + | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow + | +note: the lint level is defined here + --> $DIR/const-eval-overflow2c.rs:8:9 + | +LL | #![deny(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index b74d5a2722bd8..0ae7bfa86bc76 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/const-eval-query-stack.rs:19:16 | LL | const X: i32 = 1 / 0; - | ---------------^^^^^- - | | - | attempt to divide `1_i32` by zero + | ------------ ^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/const-eval-query-stack.rs:18:8 @@ -35,3 +33,29 @@ query stack during panic: #1 [optimized_mir] optimizing MIR for `main` #2 [collect_and_partition_mono_items] collect_and_partition_mono_items end of query stack +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const-eval-query-stack.rs:19:16 + | +LL | const X: i32 = 1 / 0; + | ------------ ^^^^^ attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/const-eval-query-stack.rs:18:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: erroneous constant used + --> $DIR/const-eval-query-stack.rs:23:27 + | +LL | let x: &'static i32 = &X; + | ^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index c19f6342b5ba6..655a7d520545c 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:26:49 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | --------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -14,9 +12,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:30:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -25,9 +21,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:34:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -36,9 +30,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:38:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -47,9 +39,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:42:45 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -58,7 +48,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:46:5 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 16, align: 8) { @@ -69,9 +59,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:49:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -80,9 +68,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:53:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -91,9 +77,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:57:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -102,9 +86,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:61:45 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -113,7 +95,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:65:5 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 16, align: 8) { @@ -124,9 +106,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:68:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -135,9 +115,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:72:45 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -146,9 +124,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:76:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; - | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -157,9 +133,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:80:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; - | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -168,9 +142,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:84:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; - | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -179,9 +151,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:88:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -190,9 +160,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:92:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -201,9 +169,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:96:41 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -212,9 +178,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:100:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -223,9 +187,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:104:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; - | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ---------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -234,9 +196,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:108:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -245,9 +205,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:112:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -256,9 +214,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:116:41 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -267,9 +223,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:120:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -278,9 +232,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:124:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -289,9 +241,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:128:41 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -300,9 +250,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:132:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -311,9 +259,7 @@ error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:136:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -321,3 +267,300 @@ LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.charact error: aborting due to 29 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:26:49 + | +LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; + | -------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:30:43 + | +LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:34:45 + | +LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:38:45 + | +LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:42:45 + | +LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:49:43 + | +LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:53:45 + | +LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:57:45 + | +LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:61:45 + | +LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:68:45 + | +LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:72:45 + | +LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; + | ---------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:76:47 + | +LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; + | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:80:47 + | +LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; + | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:84:39 + | +LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; + | ---------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:88:41 + | +LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:92:41 + | +LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:96:41 + | +LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:100:43 + | +LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:104:39 + | +LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; + | ---------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:108:41 + | +LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:112:41 + | +LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:116:41 + | +LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:120:43 + | +LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:124:41 + | +LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:128:41 + | +LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; + | ------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:132:43 + | +LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-pointer-values-in-various-types.rs:136:43 + | +LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr index c17166263ba09..f6ffa1ef2969e 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -21,3 +21,79 @@ LL | x(y) error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_fn_ptr_fail2.rs:12:5 + | +LL | x(y) + | ^^^^ + | | + | calling non-const function `double` + | inside `bar` at $DIR/const_fn_ptr_fail2.rs:12:5 + | inside `Y` at $DIR/const_fn_ptr_fail2.rs:15:18 +... +LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday + | -------------- + | +note: the lint level is defined here + --> $DIR/const_fn_ptr_fail2.rs:4:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_fn_ptr_fail2.rs:12:5 + | +LL | x(y) + | ^^^^ + | | + | calling non-const function `double` + | inside `bar` at $DIR/const_fn_ptr_fail2.rs:12:5 + | inside `Z` at $DIR/const_fn_ptr_fail2.rs:16:18 +... +LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday + | -------------- + | +note: the lint level is defined here + --> $DIR/const_fn_ptr_fail2.rs:4:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: erroneous constant used + --> $DIR/const_fn_ptr_fail2.rs:19:5 + | +LL | assert_eq!(Y, 4); + | ^^^^^^^^^^^^^^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/const_fn_ptr_fail2.rs:4:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: erroneous constant used + --> $DIR/const_fn_ptr_fail2.rs:21:5 + | +LL | assert_eq!(Z, 4); + | ^^^^^^^^^^^^^^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/const_fn_ptr_fail2.rs:4:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr b/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr index 94cf64fff1999..f06dedc229845 100644 --- a/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr +++ b/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr @@ -5,9 +5,9 @@ LL | panic!({ "foo" }); | ^^^^^^^^^ | = note: `#[warn(non_fmt_panics)]` on by default - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", { "foo" }); | +++++ diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs index c3f8b9f31ea8d..ec5508a1e90c9 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -5,6 +5,6 @@ const Z: i32 = unsafe { *(&1 as *const i32) }; // bad, will thus error in miri const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| is not a valid pointer +//~| is a dangling pointer const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| is not a valid pointer +//~| is a dangling pointer diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr index df8a80be72cb5..e41dea873ac1a 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:9:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr index 7e2a60929c73d..adfb4cc61cc62 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const.stderr @@ -14,9 +14,7 @@ warning: any use of this value will cause an error --> $DIR/erroneous-const.rs:6:22 | LL | const VOID: () = [()][2]; - | -----------------^^^^^^^- - | | - | index out of bounds: the length is 1 but the index is 2 + | -------------- ^^^^^^^ index out of bounds: the length is 1 but the index is 2 | note: the lint level is defined here --> $DIR/erroneous-const.rs:2:9 @@ -41,3 +39,18 @@ LL | pub static FOO: () = no_codegen::<i32>(); error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/erroneous-const.rs:6:22 + | +LL | const VOID: () = [()][2]; + | -------------- ^^^^^^^ index out of bounds: the length is 1 but the index is 2 + | +note: the lint level is defined here + --> $DIR/erroneous-const.rs:2:9 + | +LL | #![warn(const_err, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/erroneous-const2.stderr b/src/test/ui/consts/const-eval/erroneous-const2.stderr index 813d3ee249fb2..e947d93e40582 100644 --- a/src/test/ui/consts/const-eval/erroneous-const2.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const2.stderr @@ -14,9 +14,7 @@ warning: any use of this value will cause an error --> $DIR/erroneous-const2.rs:6:22 | LL | const VOID: () = [()][2]; - | -----------------^^^^^^^- - | | - | index out of bounds: the length is 1 but the index is 2 + | -------------- ^^^^^^^ index out of bounds: the length is 1 but the index is 2 | note: the lint level is defined here --> $DIR/erroneous-const2.rs:2:9 @@ -35,3 +33,18 @@ LL | let _ = PrintName::<i32>::VOID; error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/erroneous-const2.rs:6:22 + | +LL | const VOID: () = [()][2]; + | -------------- ^^^^^^^ index out of bounds: the length is 1 but the index is 2 + | +note: the lint level is defined here + --> $DIR/erroneous-const2.rs:2:9 + | +LL | #![warn(const_err, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/format.stderr b/src/test/ui/consts/const-eval/format.stderr index 44f436ae4e3a9..b00cadcea991f 100644 --- a/src/test/ui/consts/const-eval/format.stderr +++ b/src/test/ui/consts/const-eval/format.stderr @@ -76,3 +76,49 @@ LL | println!("{:?}", 0); error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0015`. +Future incompatibility report: Future breakage diagnostic: +error: erroneous constant used + --> $DIR/format.rs:2:12 + | +LL | panic!("{:?}", 0); + | ^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: erroneous constant used + --> $DIR/format.rs:2:20 + | +LL | panic!("{:?}", 0); + | ^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this error originates in the macro `$crate::const_format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +error: erroneous constant used + --> $DIR/format.rs:11:14 + | +LL | println!("{:?}", 0); + | ^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: erroneous constant used + --> $DIR/format.rs:11:22 + | +LL | println!("{:?}", 0); + | ^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr index adaa4716f1532..00ab0dfc557dd 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr @@ -2,7 +2,7 @@ error: untyped pointers are not allowed in constant --> $DIR/alloc_intrinsic_nontransient_fail.rs:6:1 | LL | const FOO: *const i32 = foo(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 2ec058806ce8f..f1a780926e74b 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc_intrinsic_uninit.rs:8:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized bytes, but expected initialized bytes | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 5144378dba2db..2eb401226f876 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc_intrinsic_uninit.rs:8:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized bytes, but expected initialized bytes | = 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: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr index 8f4fea96c593d..36002b850b7e7 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -2,7 +2,7 @@ error: untyped pointers are not allowed in constant --> $DIR/alloc_intrinsic_untyped.rs:6:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr index 73664fa49d189..da4a21e08ab17 100644 --- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/index-out-of-bounds-never-type.rs:10:61 | LL | const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] }; - | --------------------------------------------------------^^^^^--- - | | - | index out of bounds: the length is 0 but the index is 0 + | ------------- ^^^^^ index out of bounds: the length is 0 but the index is 0 | note: the lint level is defined here --> $DIR/index-out-of-bounds-never-type.rs:4:9 @@ -22,3 +20,18 @@ LL | let _ = PrintName::<T>::VOID; error: aborting due to previous error; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/index-out-of-bounds-never-type.rs:10:61 + | +LL | const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] }; + | ------------- ^^^^^ index out of bounds: the length is 0 but the index is 0 + | +note: the lint level is defined here + --> $DIR/index-out-of-bounds-never-type.rs:4:9 + | +LL | #![warn(const_err, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index 32ab7c74b891f..91065f4168256 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/issue-43197.rs:10:20 | LL | const X: u32 = 0 - 1; - | ---------------^^^^^- - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow + | ------------ ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/issue-43197.rs:3:9 @@ -18,9 +16,7 @@ warning: any use of this value will cause an error --> $DIR/issue-43197.rs:13:24 | LL | const Y: u32 = foo(0 - 1); - | -------------------^^^^^-- - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow + | ------------ ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -60,3 +56,65 @@ LL | println!("{} {}", X, Y); error: aborting due to 2 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/issue-43197.rs:10:20 + | +LL | const X: u32 = 0 - 1; + | ------------ ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/issue-43197.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/issue-43197.rs:13:24 + | +LL | const Y: u32 = foo(0 - 1); + | ------------ ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/issue-43197.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: erroneous constant used + --> $DIR/issue-43197.rs:16:23 + | +LL | println!("{} {}", X, Y); + | ^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/issue-43197.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: erroneous constant used + --> $DIR/issue-43197.rs:16:26 + | +LL | println!("{} {}", X, Y); + | ^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/issue-43197.rs:3:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/consts/const-eval/issue-44578.stderr b/src/test/ui/consts/const-eval/issue-44578.stderr index bff9f40f82b35..81e563b4f5460 100644 --- a/src/test/ui/consts/const-eval/issue-44578.stderr +++ b/src/test/ui/consts/const-eval/issue-44578.stderr @@ -7,3 +7,34 @@ LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/issue-44578.rs:15:24 + | +LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; + | ---------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | +note: the lint level is defined here + --> $DIR/issue-44578.rs:3:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: erroneous constant used + --> $DIR/issue-44578.rs:27:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/issue-44578.rs:3:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr index 298f0a4a446dd..cc19caca72414 100644 --- a/src/test/ui/consts/const-eval/issue-50814-2.stderr +++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/issue-50814-2.rs:14:24 | LL | const BAR: usize = [5, 6, 7][T::BOO]; - | -------------------^^^^^^^^^^^^^^^^^- - | | - | index out of bounds: the length is 3 but the index is 42 + | ---------------- ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -25,3 +23,14 @@ LL | println!("{:x}", foo::<()>() as *const usize as usize); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/issue-50814-2.rs:14:24 + | +LL | const BAR: usize = [5, 6, 7][T::BOO]; + | ---------------- ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index 87bea28e76325..6ceef91a042aa 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/issue-50814.rs:15:21 | LL | const MAX: u8 = A::MAX + B::MAX; - | ----------------^^^^^^^^^^^^^^^- - | | - | attempt to compute `u8::MAX + u8::MAX`, which would overflow + | ------------- ^^^^^^^^^^^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -25,3 +23,14 @@ LL | foo(0); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/issue-50814.rs:15:21 + | +LL | const MAX: u8 = A::MAX + B::MAX; + | ------------- ^^^^^^^^^^^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/issue-85907.rs b/src/test/ui/consts/const-eval/issue-85907.rs new file mode 100644 index 0000000000000..6ae40ae6ddbf6 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-85907.rs @@ -0,0 +1,7 @@ +const fn hey() -> usize { + panic!(123); //~ ERROR argument to `panic!()` in a const context must have type `&str` +} + +fn main() { + let _: [u8; hey()] = todo!(); +} diff --git a/src/test/ui/consts/const-eval/issue-85907.stderr b/src/test/ui/consts/const-eval/issue-85907.stderr new file mode 100644 index 0000000000000..381f2fd1114ec --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-85907.stderr @@ -0,0 +1,10 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-85907.rs:2:5 + | +LL | panic!(123); + | ^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/issue-91827-extern-types.rs b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs index d5576ebfd0296..e1f5e8ae1453c 100644 --- a/src/test/ui/consts/const-eval/issue-91827-extern-types.rs +++ b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs @@ -4,7 +4,6 @@ // Regression test for issue #91827. #![feature(const_ptr_offset_from)] -#![feature(const_slice_from_raw_parts)] #![feature(extern_types)] use std::ptr::addr_of; diff --git a/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr b/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr index a18c7e78d95af..b007dda246de3 100644 --- a/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ b/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -1,16 +1,11 @@ error: any use of this value will cause an error --> $DIR/partial_ptr_overwrite.rs:8:9 | -LL | / const PARTIAL_OVERWRITE: () = { -LL | | let mut p = &42; -LL | | unsafe { -LL | | let ptr: *mut _ = &mut p; -LL | | *(ptr as *mut u8) = 123; - | | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4 -... | -LL | | let x = *p; -LL | | }; - | |__- +LL | const PARTIAL_OVERWRITE: () = { + | --------------------------- +... +LL | *(ptr as *mut u8) = 123; + | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -18,3 +13,17 @@ LL | | }; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/partial_ptr_overwrite.rs:8:9 + | +LL | const PARTIAL_OVERWRITE: () = { + | --------------------------- +... +LL | *(ptr as *mut u8) = 123; + | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr index 5bfd4ef92a975..cfca8ef07464f 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -43,21 +43,15 @@ LL | [1, 2, 3][4] warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:15:5 | -LL | 0 - 1 - | ^^^^^ - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow - | inside `overflow` at $DIR/promoted_errors.rs:15:5 - | inside `X` at $DIR/promoted_errors.rs:43:29 +LL | 0 - 1 + | ^^^^^ + | | + | attempt to compute `0_u32 - 1_u32`, which would overflow + | inside `overflow` at $DIR/promoted_errors.rs:15:5 + | inside `X` at $DIR/promoted_errors.rs:43:29 ... -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | const X: () = { + | ----------- | note: the lint level is defined here --> $DIR/promoted_errors.rs:11:9 @@ -70,18 +64,52 @@ LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:43:28 | -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); - | | ^^^^^^^^^^^ referenced constant has errors -LL | | -LL | | -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | const X: () = { + | ----------- +LL | let _x: &'static u32 = &overflow(); + | ^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> warning: 7 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:15:5 + | +LL | 0 - 1 + | ^^^^^ + | | + | attempt to compute `0_u32 - 1_u32`, which would overflow + | inside `overflow` at $DIR/promoted_errors.rs:15:5 + | inside `X` at $DIR/promoted_errors.rs:43:29 +... +LL | const X: () = { + | ----------- + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:43:28 + | +LL | const X: () = { + | ----------- +LL | let _x: &'static u32 = &overflow(); + | ^^^^^^^^^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr index 0a8a8aef3cf8f..984484a850f46 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -43,21 +43,15 @@ LL | [1, 2, 3][4] warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:21:5 | -LL | 1 / 0 - | ^^^^^ - | | - | attempt to divide `1_i32` by zero - | inside `div_by_zero1` at $DIR/promoted_errors.rs:21:5 - | inside `X` at $DIR/promoted_errors.rs:46:29 +LL | 1 / 0 + | ^^^^^ + | | + | attempt to divide `1_i32` by zero + | inside `div_by_zero1` at $DIR/promoted_errors.rs:21:5 + | inside `X` at $DIR/promoted_errors.rs:46:29 ... -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | const X: () = { + | ----------- | note: the lint level is defined here --> $DIR/promoted_errors.rs:11:9 @@ -70,19 +64,54 @@ LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:46:28 | -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | -LL | | let _x: &'static i32 = &div_by_zero1(); - | | ^^^^^^^^^^^^^^^ referenced constant has errors -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | const X: () = { + | ----------- +... +LL | let _x: &'static i32 = &div_by_zero1(); + | ^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> warning: 7 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:21:5 + | +LL | 1 / 0 + | ^^^^^ + | | + | attempt to divide `1_i32` by zero + | inside `div_by_zero1` at $DIR/promoted_errors.rs:21:5 + | inside `X` at $DIR/promoted_errors.rs:46:29 +... +LL | const X: () = { + | ----------- + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:46:28 + | +LL | const X: () = { + | ----------- +... +LL | let _x: &'static i32 = &div_by_zero1(); + | ^^^^^^^^^^^^^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr index 5bfd4ef92a975..cfca8ef07464f 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -43,21 +43,15 @@ LL | [1, 2, 3][4] warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:15:5 | -LL | 0 - 1 - | ^^^^^ - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow - | inside `overflow` at $DIR/promoted_errors.rs:15:5 - | inside `X` at $DIR/promoted_errors.rs:43:29 +LL | 0 - 1 + | ^^^^^ + | | + | attempt to compute `0_u32 - 1_u32`, which would overflow + | inside `overflow` at $DIR/promoted_errors.rs:15:5 + | inside `X` at $DIR/promoted_errors.rs:43:29 ... -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); -LL | | -LL | | -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | const X: () = { + | ----------- | note: the lint level is defined here --> $DIR/promoted_errors.rs:11:9 @@ -70,18 +64,52 @@ LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:43:28 | -LL | / const X: () = { -LL | | let _x: &'static u32 = &overflow(); - | | ^^^^^^^^^^^ referenced constant has errors -LL | | -LL | | -... | -LL | | let _x: &'static i32 = &oob(); -LL | | }; - | |__- +LL | const X: () = { + | ----------- +LL | let _x: &'static u32 = &overflow(); + | ^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> warning: 7 warnings emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:15:5 + | +LL | 0 - 1 + | ^^^^^ + | | + | attempt to compute `0_u32 - 1_u32`, which would overflow + | inside `overflow` at $DIR/promoted_errors.rs:15:5 + | inside `X` at $DIR/promoted_errors.rs:43:29 +... +LL | const X: () = { + | ----------- + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:43:28 + | +LL | const X: () = { + | ----------- +LL | let _x: &'static u32 = &overflow(); + | ^^^^^^^^^^^ referenced constant has errors + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:11:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr index dd47dca2b2e40..36197a7ab598e 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/pub_const_err.rs:6:20 | LL | pub const Z: u32 = 0 - 1; - | -------------------^^^^^- - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow + | ---------------- ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/pub_const_err.rs:2:9 @@ -16,3 +14,18 @@ LL | #![warn(const_err)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/pub_const_err.rs:6:20 + | +LL | pub const Z: u32 = 0 - 1; + | ---------------- ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/pub_const_err.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr index 9f413fb8fd770..2eef3b8f5c418 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/pub_const_err_bin.rs:4:20 | LL | pub const Z: u32 = 0 - 1; - | -------------------^^^^^- - | | - | attempt to compute `0_u32 - 1_u32`, which would overflow + | ---------------- ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/pub_const_err_bin.rs:2:9 @@ -16,3 +14,18 @@ LL | #![warn(const_err)] warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/pub_const_err_bin.rs:4:20 + | +LL | pub const Z: u32 = 0 - 1; + | ---------------- ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow + | +note: the lint level is defined here + --> $DIR/pub_const_err_bin.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr index 83ac6c90a43a8..0e37435881009 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/ref_to_int_match.rs:25:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | --------------------------^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------- ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -24,3 +22,14 @@ LL | 10..=BAR => {}, error: aborting due to 3 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ref_to_int_match.rs:25:27 + | +LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; + | -------------- ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr index 83ac6c90a43a8..0e37435881009 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/ref_to_int_match.rs:25:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; - | --------------------------^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------- ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -24,3 +22,14 @@ LL | 10..=BAR => {}, error: aborting due to 3 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ref_to_int_match.rs:25:27 + | +LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; + | -------------- ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/transmute-const.32bit.stderr b/src/test/ui/consts/const-eval/transmute-const.32bit.stderr index 89c7220788324..09fd79986958d 100644 --- a/src/test/ui/consts/const-eval/transmute-const.32bit.stderr +++ b/src/test/ui/consts/const-eval/transmute-const.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/transmute-const.rs:4:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean | = 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: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/transmute-const.64bit.stderr b/src/test/ui/consts/const-eval/transmute-const.64bit.stderr index 89c7220788324..09fd79986958d 100644 --- a/src/test/ui/consts/const-eval/transmute-const.64bit.stderr +++ b/src/test/ui/consts/const-eval/transmute-const.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/transmute-const.rs:4:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean | = 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: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr b/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr index d5a1f1dad618c..8560112ae3b70 100644 --- a/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -1,14 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum-overwrite.rs:8:1 | -LL | / const _: u8 = { -LL | | -LL | | let mut e = E::A(1); -LL | | let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() }; -... | -LL | | unsafe { *p } -LL | | }; - | |__^ type validation failed: encountered uninitialized bytes, but expected initialized bytes +LL | const _: u8 = { + | ^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr index c6fa14d0534f4..2f8b44da0fc9b 100644 --- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag | = 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: 4, align: 4) { @@ -13,7 +13,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:26:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -23,7 +23,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -32,7 +32,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:43:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag | = 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: 4, align: 4) { @@ -43,7 +43,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:45:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -52,7 +52,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:49:1 | LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -61,7 +61,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:59:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered uninitialized bytes, but expected initialized bytes | = 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: 4, align: 4) { @@ -72,7 +72,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:63:1 | LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -81,7 +81,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:81:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!` | = 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: 1, align: 1) { @@ -92,7 +92,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:83:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never | = 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: 1, align: 1) { @@ -103,7 +103,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:91:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = 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: 8, align: 4) { @@ -125,3 +125,58 @@ LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:26:1 + | +LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:30:1 + | +LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:45:1 + | +LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:49:1 + | +LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:63:1 + | +LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr index 25be593ab83b0..3a05a5150f1a7 100644 --- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag | = 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: 8, align: 8) { @@ -13,7 +13,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:26:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -23,7 +23,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -32,7 +32,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:43:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag | = 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: 8, align: 8) { @@ -43,7 +43,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:45:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -52,7 +52,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:49:1 | LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -61,7 +61,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:59:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered uninitialized bytes, but expected initialized bytes | = 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: 8, align: 8) { @@ -72,7 +72,7 @@ error: any use of this value will cause an error --> $DIR/ub-enum.rs:63:1 | LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -81,7 +81,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:81:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(B)>.0: encountered a value of the never type `!` | = 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: 1, align: 1) { @@ -92,7 +92,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:83:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(D)>.0: encountered a value of uninhabited type Never | = 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: 1, align: 1) { @@ -103,7 +103,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:91:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = 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: 8, align: 4) { @@ -125,3 +125,58 @@ LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:26:1 + | +LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:30:1 + | +LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:45:1 + | +LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:49:1 + | +LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-enum.rs:63:1 + | +LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index ffde14f894e65..c6422447a4b79 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -13,9 +13,8 @@ LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:34:1 | -LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = -LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; - | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2 +LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 | = 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: 8, align: 4) { @@ -25,9 +24,8 @@ LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1us error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:39:1 | -LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = -LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; - | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object +LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object | = 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: 8, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index 2ad164a8c35f7..e594ad71b5b48 100644 --- a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -13,9 +13,8 @@ LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:34:1 | -LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = -LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; - | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2 +LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 | = 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: 16, align: 8) { @@ -25,9 +24,8 @@ LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1us error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:39:1 | -LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = -LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; - | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object +LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr b/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr index df02bdaa33cd9..8eece9e30e4b0 100644 --- a/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr @@ -1,14 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-int-array.rs:14:1 | -LL | / const UNINIT_INT_0: [u32; 3] = unsafe { -LL | | -LL | | -LL | | [ -... | -LL | | ] -LL | | }; - | |__^ type validation failed at [0]: encountered uninitialized bytes +LL | const UNINIT_INT_0: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized bytes | = 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: 12, align: 4) { @@ -18,14 +12,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-int-array.rs:23:1 | -LL | / const UNINIT_INT_1: [u32; 3] = unsafe { -LL | | -LL | | -LL | | mem::transmute( -... | -LL | | ) -LL | | }; - | |__^ type validation failed at [1]: encountered uninitialized bytes +LL | const UNINIT_INT_1: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized bytes | = 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: 12, align: 4) { @@ -35,14 +23,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-int-array.rs:43:1 | -LL | / const UNINIT_INT_2: [u32; 3] = unsafe { -LL | | -LL | | -LL | | mem::transmute( -... | -LL | | ) -LL | | }; - | |__^ type validation failed at [2]: encountered uninitialized bytes +LL | const UNINIT_INT_2: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized bytes | = 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: 12, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr b/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr index df02bdaa33cd9..8eece9e30e4b0 100644 --- a/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr @@ -1,14 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-int-array.rs:14:1 | -LL | / const UNINIT_INT_0: [u32; 3] = unsafe { -LL | | -LL | | -LL | | [ -... | -LL | | ] -LL | | }; - | |__^ type validation failed at [0]: encountered uninitialized bytes +LL | const UNINIT_INT_0: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized bytes | = 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: 12, align: 4) { @@ -18,14 +12,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-int-array.rs:23:1 | -LL | / const UNINIT_INT_1: [u32; 3] = unsafe { -LL | | -LL | | -LL | | mem::transmute( -... | -LL | | ) -LL | | }; - | |__^ type validation failed at [1]: encountered uninitialized bytes +LL | const UNINIT_INT_1: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized bytes | = 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: 12, align: 4) { @@ -35,14 +23,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-int-array.rs:43:1 | -LL | / const UNINIT_INT_2: [u32; 3] = unsafe { -LL | | -LL | | -LL | | mem::transmute( -... | -LL | | ) -LL | | }; - | |__^ type validation failed at [2]: encountered uninitialized bytes +LL | const UNINIT_INT_2: [u32; 3] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [2]: encountered uninitialized bytes | = 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: 12, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-int-array.rs b/src/test/ui/consts/const-eval/ub-int-array.rs index 7e0fb33bc1187..1221f71d1e5b6 100644 --- a/src/test/ui/consts/const-eval/ub-int-array.rs +++ b/src/test/ui/consts/const-eval/ub-int-array.rs @@ -13,7 +13,7 @@ union MaybeUninit<T: Copy> { const UNINIT_INT_0: [u32; 3] = unsafe { //~^ ERROR it is undefined behavior to use this value -//~| type validation failed at [0]: encountered uninitialized bytes +//~| constructing invalid value at [0]: encountered uninitialized bytes [ MaybeUninit { uninit: () }.init, 1, @@ -22,7 +22,7 @@ const UNINIT_INT_0: [u32; 3] = unsafe { }; const UNINIT_INT_1: [u32; 3] = unsafe { //~^ ERROR it is undefined behavior to use this value -//~| type validation failed at [1]: encountered uninitialized bytes +//~| constructing invalid value at [1]: encountered uninitialized bytes mem::transmute( [ 0u8, @@ -42,7 +42,7 @@ const UNINIT_INT_1: [u32; 3] = unsafe { }; const UNINIT_INT_2: [u32; 3] = unsafe { //~^ ERROR it is undefined behavior to use this value -//~| type validation failed at [2]: encountered uninitialized bytes +//~| constructing invalid value at [2]: encountered uninitialized bytes mem::transmute( [ 0u8, diff --git a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr index e5091397e839d..d450a814cfa73 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:12:1 | LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = 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: 4, align: 4) { @@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:23:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = 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: 1, align: 1) { @@ -30,7 +30,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:25:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = 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: 4, align: 4) { @@ -41,7 +41,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:33:1 | LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered uninitialized bytes, but expected initialized bytes | = 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: 1, align: 1) { @@ -52,7 +52,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:41:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 | = 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: 4, align: 4) { @@ -63,7 +63,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:47:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr index 80c694fc83ed1..ed0d91aabd33b 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:12:1 | LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = 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: 8, align: 8) { @@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:23:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = 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: 1, align: 1) { @@ -30,7 +30,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:25:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = 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: 8, align: 8) { @@ -41,7 +41,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:33:1 | LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered uninitialized bytes, but expected initialized bytes | = 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: 1, align: 1) { @@ -52,7 +52,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:41:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 | = 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: 4, align: 4) { @@ -63,7 +63,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:47:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr index 8a4f23c033e89..2cae35bc4d0ed 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:13:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = 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: 4, align: 4) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:17:1 | LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) | = 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: 4, align: 4) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:21:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference | = 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: 4, align: 4) { @@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:24:1 | LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box | = 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: 4, align: 4) { @@ -46,7 +46,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:31:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -56,9 +56,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:35:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | unable to turn pointer into raw bytes + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -67,9 +65,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:35:38 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | -------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -78,9 +74,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:41:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | -------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^---- - | | - | unable to turn pointer into raw bytes + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -89,9 +83,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:41:85 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^---- - | | - | referenced constant has errors + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -100,7 +92,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:47:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x539 is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated) | = 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: 4, align: 4) { @@ -111,7 +103,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:50:1 | LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (address 0x539 is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated) | = 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: 4, align: 4) { @@ -122,7 +114,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:53:1 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized raw pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized raw pointer | = 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: 4, align: 4) { @@ -133,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:56:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | = 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: 4, align: 4) { @@ -144,7 +136,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:58:1 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value | = 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: 4, align: 4) { @@ -155,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:60:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000d, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x0000000d, but expected a function pointer | = 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: 4, align: 4) { @@ -166,13 +158,68 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:62:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc43, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer | = 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: 4, align: 4) { - ╾─alloc43─╼ │ ╾──╼ + ╾─alloc41─╼ │ ╾──╼ } error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:31:1 + | +LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:35:39 + | +LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:35:38 + | +LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:41:86 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:41:85 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr index da1c6d1a07f84..e2cd0e64db806 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:13:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | = 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: 8, align: 8) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:17:1 | LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) | = 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: 8, align: 8) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:21:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference | = 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: 8, align: 8) { @@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:24:1 | LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box | = 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: 8, align: 8) { @@ -46,7 +46,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:31:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -56,9 +56,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:35:39 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | unable to turn pointer into raw bytes + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -67,9 +65,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:35:38 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | -------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -78,9 +74,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:41:86 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | -------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^---- - | | - | unable to turn pointer into raw bytes + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -89,9 +83,7 @@ error: any use of this value will cause an error --> $DIR/ub-ref-ptr.rs:41:85 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^---- - | | - | referenced constant has errors + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -100,7 +92,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:47:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x539 is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x539 is unallocated) | = 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: 8, align: 8) { @@ -111,7 +103,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:50:1 | LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (address 0x539 is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (address 0x539 is unallocated) | = 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: 8, align: 8) { @@ -122,7 +114,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:53:1 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized raw pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized raw pointer | = 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: 8, align: 8) { @@ -133,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:56:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | = 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: 8, align: 8) { @@ -144,7 +136,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:58:1 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value | = 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: 8, align: 8) { @@ -155,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:60:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x000000000000000d, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x000000000000000d, but expected a function pointer | = 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: 8, align: 8) { @@ -166,13 +158,68 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:62:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc43, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer | = 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: 8, align: 8) { - ╾───────alloc43───────╼ │ ╾──────╼ + ╾───────alloc41───────╼ │ ╾──────╼ } error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:31:1 + | +LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:35:39 + | +LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:35:38 + | +LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; + | ---------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:41:86 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-ref-ptr.rs:41:85 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ------------------------------------------ ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.rs b/src/test/ui/consts/const-eval/ub-ref-ptr.rs index 17b0d29c51490..d0216f7466896 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.rs @@ -12,11 +12,11 @@ union MaybeUninit<T: Copy> { const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; //~^ ERROR it is undefined behavior to use this value -//~| type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) +//~| constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; //~^ ERROR it is undefined behavior to use this value -//~| type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) +//~| constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr index 7873b3463c117..7f0feb1300494 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:15:1 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^ 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: 0, align: 1) {} @@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to 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: 4, align: 4) { @@ -22,7 +22,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: 0, align: 1) {} diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr index 473497501113c..4dcbbc2f5e41b 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:15:1 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^ 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: 0, align: 1) {} @@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to 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: 8, align: 8) { @@ -22,7 +22,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: 0, align: 1) {} diff --git a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr index 27b98c2547ce7..43f73f6ec7f27 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -1,12 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-upvars.rs:6:1 | -LL | / const BAD_UPVAR: &dyn FnOnce() = &{ -LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; -LL | | let another_var = 13; -LL | | move || { let _ = bad_ref; let _ = another_var; } -LL | | }; - | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference +LL | const BAD_UPVAR: &dyn FnOnce() = &{ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference | = 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: 8, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr index 9cc9fb59bd7f0..64185a0636297 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -1,12 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-upvars.rs:6:1 | -LL | / const BAD_UPVAR: &dyn FnOnce() = &{ -LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; -LL | | let another_var = 13; -LL | | move || { let _ = bad_ref; let _ = another_var; } -LL | | }; - | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference +LL | const BAD_UPVAR: &dyn FnOnce() = &{ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index a78cff11589fd..2fd98ea322b02 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:37:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = 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: 8, align: 4) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:39:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 8, align: 4) { @@ -24,7 +24,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:42:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -34,7 +34,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:46:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -43,7 +43,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:49:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 8, align: 4) { @@ -54,7 +54,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:53:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str` | = 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: 8, align: 4) { @@ -65,7 +65,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:56:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str` | = 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: 8, align: 4) { @@ -75,12 +75,8 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:63:1 | -LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe { -LL | | -LL | | let uninit_len = MaybeUninit::<usize> { uninit: () }; -LL | | mem::transmute((42, uninit_len)) -LL | | }; - | |__^ type validation failed: encountered uninitialized reference +LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized reference | = 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: 8, align: 4) { @@ -91,7 +87,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:69:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = 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: 8, align: 4) { @@ -102,7 +98,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:72:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 8, align: 4) { @@ -113,7 +109,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -122,7 +118,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:79:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) | = 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: 8, align: 4) { @@ -133,7 +129,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:82:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -142,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:87:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean | = 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: 4, align: 4) { @@ -153,9 +149,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:87:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | ------------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -164,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:95:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean | = 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: 4, align: 4) { @@ -175,9 +169,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:95:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -186,7 +178,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:100:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean | = 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: 4, align: 4) { @@ -197,9 +189,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:100:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -207,12 +197,8 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:109:1 | -LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { -LL | | -LL | | let uninit_len = MaybeUninit::<usize> { uninit: () }; -LL | | mem::transmute((42, uninit_len)) -LL | | }; - | |__^ type validation failed: encountered uninitialized raw pointer +LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized raw pointer | = 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: 8, align: 4) { @@ -223,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = 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: 8, align: 4) { @@ -234,7 +220,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = 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: 8, align: 4) { @@ -245,7 +231,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer | = 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: 8, align: 4) { @@ -256,7 +242,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:125:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer | = 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: 8, align: 4) { @@ -267,7 +253,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | = 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: 8, align: 4) { @@ -278,7 +264,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:129:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | = 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: 8, align: 4) { @@ -289,7 +275,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:131:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | = 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: 8, align: 4) { @@ -300,7 +286,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:135:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean | = 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: 8, align: 4) { @@ -311,7 +297,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:139:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer | = 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: 8, align: 4) { @@ -322,7 +308,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:141:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable | = 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: 8, align: 4) { @@ -333,7 +319,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:147:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:151:5 @@ -344,3 +330,80 @@ LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) error: aborting due to 32 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:42:1 + | +LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:46:1 + | +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:75:1 + | +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:82:1 + | +LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:87:40 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ------------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:95:42 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:100:42 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index 69a61d9caede6..bae249076598e 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:37:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = 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: 16, align: 8) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:39:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 16, align: 8) { @@ -24,7 +24,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:42:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -34,7 +34,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:46:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -43,7 +43,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:49:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 16, align: 8) { @@ -54,7 +54,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:53:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized data in `str` | = 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: 16, align: 8) { @@ -65,7 +65,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:56:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized data in `str` | = 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: 16, align: 8) { @@ -75,12 +75,8 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:63:1 | -LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe { -LL | | -LL | | let uninit_len = MaybeUninit::<usize> { uninit: () }; -LL | | mem::transmute((42, uninit_len)) -LL | | }; - | |__^ type validation failed: encountered uninitialized reference +LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized reference | = 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: 16, align: 8) { @@ -91,7 +87,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:69:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = 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: 16, align: 8) { @@ -102,7 +98,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:72:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 16, align: 8) { @@ -113,7 +109,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -122,7 +118,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:79:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) | = 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: 16, align: 8) { @@ -133,7 +129,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:82:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -142,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:87:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean | = 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: 8, align: 8) { @@ -153,9 +149,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:87:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | ------------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -164,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:95:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean | = 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: 8, align: 8) { @@ -175,9 +169,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:95:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -186,7 +178,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:100:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean | = 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: 8, align: 8) { @@ -197,9 +189,7 @@ error: any use of this value will cause an error --> $DIR/ub-wide-ptr.rs:100:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | referenced constant has errors + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -207,12 +197,8 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:109:1 | -LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { -LL | | -LL | | let uninit_len = MaybeUninit::<usize> { uninit: () }; -LL | | mem::transmute((42, uninit_len)) -LL | | }; - | |__^ type validation failed: encountered uninitialized raw pointer +LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized raw pointer | = 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: 16, align: 8) { @@ -223,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = 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: 16, align: 8) { @@ -234,7 +220,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:120:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | = 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: 16, align: 8) { @@ -245,7 +231,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer | = 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: 16, align: 8) { @@ -256,7 +242,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:125:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer | = 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: 16, align: 8) { @@ -267,7 +253,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | = 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: 16, align: 8) { @@ -278,7 +264,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:129:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | = 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: 16, align: 8) { @@ -289,7 +275,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:131:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | = 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: 16, align: 8) { @@ -300,7 +286,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:135:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean | = 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: 16, align: 8) { @@ -311,7 +297,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:139:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer | = 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: 16, align: 8) { @@ -322,7 +308,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:141:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable | = 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: 16, align: 8) { @@ -333,7 +319,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:147:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:151:5 @@ -344,3 +330,80 @@ LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) error: aborting due to 32 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:42:1 + | +LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:46:1 + | +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:75:1 + | +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:82:1 + | +LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:87:40 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ------------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:95:42 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ub-wide-ptr.rs:100:42 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | -------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.stderr b/src/test/ui/consts/const-eval/union-const-eval-field.stderr index 94ab6eeff28c1..c512e6825042f 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.stderr +++ b/src/test/ui/consts/const-eval/union-const-eval-field.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-const-eval-field.rs:28:5 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index 7f77f2c16aeb0..21a54550900bb 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ice.rs:14:1 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = 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: 8, align: 8) { @@ -12,11 +12,8 @@ LL | const FIELD3: Field3 = unsafe { UNION.field3 }; error[E0080]: it is undefined behavior to use this value --> $DIR/union-ice.rs:16:1 | -LL | / const FIELD_PATH: Struct = Struct { -LL | | a: 42, -LL | | b: unsafe { UNION.field3 }, -LL | | }; - | |__^ type validation failed at .b: encountered uninitialized bytes, but expected initialized bytes +LL | const FIELD_PATH: Struct = Struct { + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .b: encountered uninitialized bytes, but expected initialized bytes | = 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: 16, align: 8) { @@ -26,14 +23,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/union-ice.rs:26:1 | -LL | / const FIELD_PATH2: Struct2 = Struct2 { -LL | | b: [ -LL | | 21, -LL | | unsafe { UNION.field3 }, -... | -LL | | a: 42, -LL | | }; - | |__^ type validation failed at .b[1]: encountered uninitialized bytes +LL | const FIELD_PATH2: Struct2 = Struct2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .b[1]: encountered uninitialized bytes | = 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: 40, align: 8) { diff --git a/src/test/ui/consts/const-eval/union-ub.32bit.stderr b/src/test/ui/consts/const-eval/union-ub.32bit.stderr index d3e4bad968bd0..baf6825966007 100644 --- a/src/test/ui/consts/const-eval/union-ub.32bit.stderr +++ b/src/test/ui/consts/const-eval/union-ub.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub.rs:33:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x2a, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x2a, but expected a boolean | = 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: 1, align: 1) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub.rs:35:1 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a boolean | = 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: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/union-ub.64bit.stderr b/src/test/ui/consts/const-eval/union-ub.64bit.stderr index d3e4bad968bd0..baf6825966007 100644 --- a/src/test/ui/consts/const-eval/union-ub.64bit.stderr +++ b/src/test/ui/consts/const-eval/union-ub.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub.rs:33:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x2a, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x2a, but expected a boolean | = 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: 1, align: 1) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub.rs:35:1 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a boolean | = 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: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr index 2ce60ec16a33f..df5bd524f2727 100644 --- a/src/test/ui/consts/const-eval/unused-broken-const.stderr +++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/unused-broken-const.rs:5:18 | LL | const FOO: i32 = [][0]; - | -----------------^^^^^- - | | - | index out of bounds: the length is 0 but the index is 0 + | -------------- ^^^^^ index out of bounds: the length is 0 but the index is 0 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const FOO: i32 = [][0]; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/unused-broken-const.rs:5:18 + | +LL | const FOO: i32 = [][0]; + | -------------- ^^^^^ index out of bounds: the length is 0 but the index is 0 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index acb9bda31d104..bdaeb4a0fbee0 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_uninhabited_zsts.rs:23:1 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0].0: encountered a value of uninhabited type empty::Void + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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) {} diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index acb9bda31d104..bdaeb4a0fbee0 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_uninhabited_zsts.rs:23:1 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0].0: encountered a value of uninhabited type empty::Void + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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) {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr index 4cd0fd2eaf76d..34ec8aadbcf3b 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr @@ -1,16 +1,16 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/const-extern-fn-requires-unsafe.rs:9:17 + --> $DIR/const-extern-fn-requires-unsafe.rs:12:5 | -LL | let a: [u8; foo()]; - | ^^^^^ call to unsafe function +LL | foo(); + | ^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/const-extern-fn-requires-unsafe.rs:12:5 + --> $DIR/const-extern-fn-requires-unsafe.rs:9:17 | -LL | foo(); - | ^^^^^ call to unsafe function +LL | let a: [u8; foo()]; + | ^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/src/test/ui/consts/const-external-macro-const-err.stderr b/src/test/ui/consts/const-external-macro-const-err.stderr index a66d79a16160c..205ee92dfd7cf 100644 --- a/src/test/ui/consts/const-external-macro-const-err.stderr +++ b/src/test/ui/consts/const-external-macro-const-err.stderr @@ -11,3 +11,15 @@ LL | static_assert!(2 + 2 == 5); error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-external-macro-const-err.rs:12:5 + | +LL | static_assert!(2 + 2 == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this error originates in the macro `static_assert` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/consts/const-float-bits-reject-conv.stderr b/src/test/ui/consts/const-float-bits-reject-conv.stderr index f3fd098e848a2..b77c6591d4975 100644 --- a/src/test/ui/consts/const-float-bits-reject-conv.stderr +++ b/src/test/ui/consts/const-float-bits-reject-conv.stderr @@ -60,7 +60,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:30:34 | LL | const _: () = assert!($a); - | -------------------------- + | ----------- ... LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); | ^^^^^^^^^^^ referenced constant has errors @@ -73,7 +73,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:33:34 | LL | const _: () = assert!($a); - | -------------------------- + | ----------- ... LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); | ^^^^^^^^^^^ referenced constant has errors @@ -85,7 +85,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:41:38 | LL | const _: () = assert!($a == $b); - | -------------------------------- + | ----------- ... LL | const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); | ^^^^^^^^^^^ referenced constant has errors @@ -97,7 +97,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:44:38 | LL | const _: () = assert!($a == $b); - | -------------------------------- + | ----------- ... LL | const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); | ^^^^^^^^^^^ referenced constant has errors @@ -167,7 +167,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:57:34 | LL | const _: () = assert!($a); - | -------------------------- + | ----------- ... LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); | ^^^^^^^^^^^ referenced constant has errors @@ -179,7 +179,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:60:34 | LL | const _: () = assert!($a); - | -------------------------- + | ----------- ... LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); | ^^^^^^^^^^^ referenced constant has errors @@ -191,7 +191,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:66:38 | LL | const _: () = assert!($a == $b); - | -------------------------------- + | ----------- ... LL | const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); | ^^^^^^^^^^^ referenced constant has errors @@ -203,7 +203,7 @@ error: any use of this value will cause an error --> $DIR/const-float-bits-reject-conv.rs:69:38 | LL | const _: () = assert!($a == $b); - | -------------------------------- + | ----------- ... LL | const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); | ^^^^^^^^^^^ referenced constant has errors @@ -214,3 +214,115 @@ LL | const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:30:34 + | +LL | const _: () = assert!($a); + | ----------- +... +LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:33:34 + | +LL | const _: () = assert!($a); + | ----------- +... +LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:41:38 + | +LL | const _: () = assert!($a == $b); + | ----------- +... +LL | const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:44:38 + | +LL | const _: () = assert!($a == $b); + | ----------- +... +LL | const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:57:34 + | +LL | const _: () = assert!($a); + | ----------- +... +LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:60:34 + | +LL | const _: () = assert!($a); + | ----------- +... +LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan()); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:66:38 + | +LL | const _: () = assert!($a == $b); + | ----------- +... +LL | const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-float-bits-reject-conv.rs:69:38 + | +LL | const _: () = assert!($a == $b); + | ----------- +... +LL | const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2); + | ^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-len-underflow-separate-spans.stderr b/src/test/ui/consts/const-len-underflow-separate-spans.stderr index 70f645a6c40e8..d1bf4b92e6a50 100644 --- a/src/test/ui/consts/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/consts/const-len-underflow-separate-spans.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-len-underflow-separate-spans.rs:7:20 | LL | const LEN: usize = ONE - TWO; - | -------------------^^^^^^^^^- - | | - | attempt to compute `1_usize - 2_usize`, which would overflow + | ---------------- ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -19,3 +17,14 @@ LL | let a: [i8; LEN] = unimplemented!(); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-len-underflow-separate-spans.rs:7:20 + | +LL | const LEN: usize = ONE - TWO; + | ---------------- ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index e0704e24a2e68..074beaab2c4d0 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -11,7 +11,7 @@ const fn helper() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (integer as pointer), who doesn't love tests like this. // This code never gets executed, because the static checks fail before that. Some(&mut *(42 as *mut i32)) //~ ERROR evaluation of constant value failed - //~| 0x2a is not a valid pointer + //~| 0x2a[noalloc] is a dangling pointer } } // The error is an evaluation error and not a validation error, so the error is reported // directly at the site where it occurs. diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 9c1733e827d19..234e55e3a96c8 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed LL | Some(&mut *(42 as *mut i32)) | ^^^^^^^^^^^^^^^^^^^^^^ | | - | dereferencing pointer failed: 0x2a is not a valid pointer + | dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) | inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:13:10 ... LL | const A: Option<&mut i32> = helper(); @@ -14,7 +14,7 @@ error: encountered dangling pointer in final constant --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1 | LL | const B: Option<&mut i32> = helper2(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-needs_drop-monomorphic.stderr b/src/test/ui/consts/const-needs_drop-monomorphic.stderr index 6e56d20c39d7f..0874a70ce392e 100644 --- a/src/test/ui/consts/const-needs_drop-monomorphic.stderr +++ b/src/test/ui/consts/const-needs_drop-monomorphic.stderr @@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `assert` found for struct `Bo --> $DIR/const-needs_drop-monomorphic.rs:11:46 | LL | struct Bool<const B: bool> {} - | -------------------------- function or associated item `assert` not found for this + | -------------------------- function or associated item `assert` not found for this struct ... LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert(); | ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::<T>() }>` due to unsatisfied trait bounds diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr index 3e3bc1979a2e0..a2b8f072c6ea7 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.stderr +++ b/src/test/ui/consts/const-pattern-irrefutable.stderr @@ -2,7 +2,7 @@ error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8:: --> $DIR/const-pattern-irrefutable.rs:12:9 | LL | const a: u8 = 2; - | ---------------- constant defined here + | ----------- constant defined here ... LL | let a = 4; | ^ @@ -16,7 +16,7 @@ error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8:: --> $DIR/const-pattern-irrefutable.rs:13:9 | LL | pub const b: u8 = 2; - | -------------------- constant defined here + | --------------- constant defined here ... LL | let c = 4; | ^ @@ -30,7 +30,7 @@ error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8:: --> $DIR/const-pattern-irrefutable.rs:14:9 | LL | pub const d: u8 = 2; - | -------------------- constant defined here + | --------------- constant defined here ... LL | let d = 4; | ^ diff --git a/src/test/ui/consts/const-points-to-static.32bit.stderr b/src/test/ui/consts/const-points-to-static.32bit.stderr index 78af2c30d0437..97825dd0eb517 100644 --- a/src/test/ui/consts/const-points-to-static.32bit.stderr +++ b/src/test/ui/consts/const-points-to-static.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-points-to-static.rs:6:1 | LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to a static variable + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/const-points-to-static.64bit.stderr b/src/test/ui/consts/const-points-to-static.64bit.stderr index f5a0a6b0addef..0d4a5a8ce4f33 100644 --- a/src/test/ui/consts/const-points-to-static.64bit.stderr +++ b/src/test/ui/consts/const-points-to-static.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-points-to-static.rs:6:1 | LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to a static variable + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 8, align: 8) { diff --git a/src/test/ui/consts/const-prop-read-static-in-const.stderr b/src/test/ui/consts/const-prop-read-static-in-const.stderr index 94d3f1c614544..ea5ad24b0b135 100644 --- a/src/test/ui/consts/const-prop-read-static-in-const.stderr +++ b/src/test/ui/consts/const-prop-read-static-in-const.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-prop-read-static-in-const.rs:5:18 | LL | const TEST: u8 = MY_STATIC; - | -----------------^^^^^^^^^- - | | - | constant accesses static + | -------------- ^^^^^^^^^ constant accesses static | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -20,3 +18,14 @@ LL | const TEST: u8 = MY_STATIC; error: aborting due to previous error; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-prop-read-static-in-const.rs:5:18 + | +LL | const TEST: u8 = MY_STATIC; + | -------------- ^^^^^^^^^ constant accesses static + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index a9211c17a6bc0..d19a89378eca1 100644 --- a/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:31 | LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; - | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | `extern type` does not have known layout + | ------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -14,12 +12,32 @@ error: any use of this value will cause an error --> $DIR/const-size_of_val-align_of_val-extern-type.rs:13:32 | LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; - | -------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | `extern type` does not have known layout + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: aborting due to 2 previous errors +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:31 + | +LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; + | ------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:13:32 + | +LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `extern type` does not have known layout + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const-size_of_val-align_of_val.rs b/src/test/ui/consts/const-size_of_val-align_of_val.rs index 5a78313c48350..c3de6dc2075f8 100644 --- a/src/test/ui/consts/const-size_of_val-align_of_val.rs +++ b/src/test/ui/consts/const-size_of_val-align_of_val.rs @@ -2,7 +2,6 @@ #![feature(const_size_of_val, const_align_of_val)] #![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)] -#![feature(const_slice_from_raw_parts)] use std::{mem, ptr}; diff --git a/src/test/ui/consts/const-slice-oob.stderr b/src/test/ui/consts/const-slice-oob.stderr index 6d2c79034d391..27c21e7af149b 100644 --- a/src/test/ui/consts/const-slice-oob.stderr +++ b/src/test/ui/consts/const-slice-oob.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-slice-oob.rs:4:18 | LL | const BAR: u32 = FOO[5]; - | -----------------^^^^^^- - | | - | index out of bounds: the length is 3 but the index is 5 + | -------------- ^^^^^^ index out of bounds: the length is 3 but the index is 5 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const BAR: u32 = FOO[5]; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const-slice-oob.rs:4:18 + | +LL | const BAR: u32 = FOO[5]; + | -------------- ^^^^^^ index out of bounds: the length is 3 but the index is 5 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr index 5e706a4466ea1..e450f4aa3bd51 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -1,15 +1,11 @@ error: any use of this value will cause an error --> $DIR/const_eval_limit_reached.rs:6:11 | -LL | / const X: usize = { -LL | | let mut x = 0; -LL | | while x != 1000 { - | | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) -LL | | -... | -LL | | x -LL | | }; - | |__- +LL | const X: usize = { + | -------------- +LL | let mut x = 0; +LL | while x != 1000 { + | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -17,3 +13,17 @@ LL | | }; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/const_eval_limit_reached.rs:6:11 + | +LL | const X: usize = { + | -------------- +LL | let mut x = 0; +LL | while x != 1000 { + | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/dangling-alloc-id-ice.stderr b/src/test/ui/consts/dangling-alloc-id-ice.stderr index 24f5744987225..8410034c041da 100644 --- a/src/test/ui/consts/dangling-alloc-id-ice.stderr +++ b/src/test/ui/consts/dangling-alloc-id-ice.stderr @@ -1,12 +1,8 @@ error: encountered dangling pointer in final constant --> $DIR/dangling-alloc-id-ice.rs:9:1 | -LL | / const FOO: &() = { -LL | | -LL | | let y = (); -LL | | unsafe { Foo { y: &y }.long_live_the_unit } -LL | | }; - | |__^ +LL | const FOO: &() = { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/dangling_raw_ptr.stderr b/src/test/ui/consts/dangling_raw_ptr.stderr index a79ac62d5cdbd..bdfe1e4effe3e 100644 --- a/src/test/ui/consts/dangling_raw_ptr.stderr +++ b/src/test/ui/consts/dangling_raw_ptr.stderr @@ -1,11 +1,8 @@ error: encountered dangling pointer in final constant --> $DIR/dangling_raw_ptr.rs:1:1 | -LL | / const FOO: *const u32 = { -LL | | let x = 42; -LL | | &x -LL | | }; - | |__^ +LL | const FOO: *const u32 = { + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/invalid-union.32bit.stderr b/src/test/ui/consts/invalid-union.32bit.stderr index 38c38d1ae6732..ae5f6b2baee40 100644 --- a/src/test/ui/consts/invalid-union.32bit.stderr +++ b/src/test/ui/consts/invalid-union.32bit.stderr @@ -1,8 +1,8 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:40:1 + --> $DIR/invalid-union.rs:41:1 | LL | fn main() { - | ^^^^^^^^^ type validation failed at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` | = 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: 4, align: 4) { @@ -10,7 +10,7 @@ LL | fn main() { } error: erroneous constant used - --> $DIR/invalid-union.rs:41:25 + --> $DIR/invalid-union.rs:42:25 | LL | let _: &'static _ = &C; | ^^ referenced constant has errors @@ -22,3 +22,14 @@ LL | let _: &'static _ = &C; error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: erroneous constant used + --> $DIR/invalid-union.rs:42:25 + | +LL | let _: &'static _ = &C; + | ^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/invalid-union.64bit.stderr b/src/test/ui/consts/invalid-union.64bit.stderr index 6bfa97a2fded7..d50e74a16ec36 100644 --- a/src/test/ui/consts/invalid-union.64bit.stderr +++ b/src/test/ui/consts/invalid-union.64bit.stderr @@ -1,8 +1,8 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:40:1 + --> $DIR/invalid-union.rs:41:1 | LL | fn main() { - | ^^^^^^^^^ type validation failed at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` | = 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: 8, align: 8) { @@ -10,7 +10,7 @@ LL | fn main() { } error: erroneous constant used - --> $DIR/invalid-union.rs:41:25 + --> $DIR/invalid-union.rs:42:25 | LL | let _: &'static _ = &C; | ^^ referenced constant has errors @@ -22,3 +22,14 @@ LL | let _: &'static _ = &C; error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: erroneous constant used + --> $DIR/invalid-union.rs:42:25 + | +LL | let _: &'static _ = &C; + | ^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/invalid-union.rs b/src/test/ui/consts/invalid-union.rs index f3f1af89b2c41..efeddf75cb557 100644 --- a/src/test/ui/consts/invalid-union.rs +++ b/src/test/ui/consts/invalid-union.rs @@ -9,8 +9,9 @@ // build-fail // stderr-per-bitwidth #![feature(const_mut_refs)] -#![feature(untagged_unions)] + use std::cell::Cell; +use std::mem::ManuallyDrop; #[repr(C)] struct S { @@ -25,7 +26,7 @@ enum E { } union U { - cell: Cell<u32>, + cell: ManuallyDrop<Cell<u32>>, } const C: S = { diff --git a/src/test/ui/consts/issue-36163.stderr b/src/test/ui/consts/issue-36163.stderr index 9ac6c984cb0cd..4797d10b7a80c 100644 --- a/src/test/ui/consts/issue-36163.stderr +++ b/src/test/ui/consts/issue-36163.stderr @@ -8,7 +8,7 @@ note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `Foo::B::{constant#0}`, completing the cycle note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 diff --git a/src/test/ui/consts/issue-50439.rs b/src/test/ui/consts/issue-50439.rs new file mode 100644 index 0000000000000..0be7c405473ca --- /dev/null +++ b/src/test/ui/consts/issue-50439.rs @@ -0,0 +1,29 @@ +#![feature(specialization)] +#![allow(incomplete_features)] + +pub trait ReflectDrop { + const REFLECT_DROP: bool = false; +} + +impl<T> ReflectDrop for T where T: Clone {} + +pub trait PinDropInternal { + fn is_valid() + where + Self: ReflectDrop; +} + +struct Bears<T>(T); + +default impl<T> ReflectDrop for Bears<T> {} + +impl<T: Sized> PinDropInternal for Bears<T> { + fn is_valid() + where + Self: ReflectDrop, + { + let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; //~ ERROR constant expression depends on a generic parameter + } +} + +fn main() {} diff --git a/src/test/ui/consts/issue-50439.stderr b/src/test/ui/consts/issue-50439.stderr new file mode 100644 index 0000000000000..3fbdf33b2d881 --- /dev/null +++ b/src/test/ui/consts/issue-50439.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-50439.rs:25:22 + | +LL | let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr index 3b80b3486a822..73a0f8ec0d04f 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -26,3 +26,14 @@ LL | const fn foo() { (||{})() } error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0015`. +Future incompatibility report: Future breakage diagnostic: +error: erroneous constant used + --> $DIR/issue-56164.rs:1:18 + | +LL | const fn foo() { (||{})() } + | ^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/issue-63952.32bit.stderr b/src/test/ui/consts/issue-63952.32bit.stderr index 6a6097d5ec623..755c7fb7d4d9f 100644 --- a/src/test/ui/consts/issue-63952.32bit.stderr +++ b/src/test/ui/consts/issue-63952.32bit.stderr @@ -1,14 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-63952.rs:17:1 | -LL | / const SLICE_WAY_TOO_LONG: &[u8] = unsafe { -LL | | SliceTransmute { -LL | | repr: SliceRepr { -LL | | ptr: &42, -... | -LL | | .slice -LL | | }; - | |__^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object +LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 8, align: 4) { diff --git a/src/test/ui/consts/issue-63952.64bit.stderr b/src/test/ui/consts/issue-63952.64bit.stderr index 6547c3384da82..abdb9a4f7920d 100644 --- a/src/test/ui/consts/issue-63952.64bit.stderr +++ b/src/test/ui/consts/issue-63952.64bit.stderr @@ -1,14 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-63952.rs:17:1 | -LL | / const SLICE_WAY_TOO_LONG: &[u8] = unsafe { -LL | | SliceTransmute { -LL | | repr: SliceRepr { -LL | | ptr: &42, -... | -LL | | .slice -LL | | }; - | |__^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object +LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/issue-66693.stderr b/src/test/ui/consts/issue-66693.stderr index b825768498386..929f905ae918b 100644 --- a/src/test/ui/consts/issue-66693.stderr +++ b/src/test/ui/consts/issue-66693.stderr @@ -34,3 +34,14 @@ LL | panic!(&1); error: aborting due to 4 previous errors +Future incompatibility report: Future breakage diagnostic: +error: erroneous constant used + --> $DIR/issue-66693.rs:11:12 + | +LL | panic!(&1); + | ^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/issue-78655.rs b/src/test/ui/consts/issue-78655.rs index b85e612992549..82d2d7c21d859 100644 --- a/src/test/ui/consts/issue-78655.rs +++ b/src/test/ui/consts/issue-78655.rs @@ -1,6 +1,6 @@ const FOO: *const u32 = { let x; - &x //~ ERROR borrow of possibly-uninitialized variable: `x` + &x //~ ERROR E0381 }; fn main() { diff --git a/src/test/ui/consts/issue-78655.stderr b/src/test/ui/consts/issue-78655.stderr index 734266a3453b5..f5b1123e7f343 100644 --- a/src/test/ui/consts/issue-78655.stderr +++ b/src/test/ui/consts/issue-78655.stderr @@ -1,8 +1,10 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/issue-78655.rs:3:5 | +LL | let x; + | - binding declared here but left uninitialized LL | &x - | ^^ use of possibly-uninitialized `x` + | ^^ `x` used here but it isn't initialized error: could not evaluate constant pattern --> $DIR/issue-78655.rs:7:9 diff --git a/src/test/ui/consts/issue-79690.64bit.stderr b/src/test/ui/consts/issue-79690.64bit.stderr index bf0ef9e6dc07e..c7aba55537088 100644 --- a/src/test/ui/consts/issue-79690.64bit.stderr +++ b/src/test/ui/consts/issue-79690.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-79690.rs:30:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^ constructing invalid value at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/issue-83182.32bit.stderr b/src/test/ui/consts/issue-83182.32bit.stderr index a15668d4ec1b9..c810c8a7848c7 100644 --- a/src/test/ui/consts/issue-83182.32bit.stderr +++ b/src/test/ui/consts/issue-83182.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-83182.rs:5:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer in `str` | = 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: 8, align: 4) { diff --git a/src/test/ui/consts/issue-83182.64bit.stderr b/src/test/ui/consts/issue-83182.64bit.stderr index 5c3ade7c1de44..5fc2c934474dc 100644 --- a/src/test/ui/consts/issue-83182.64bit.stderr +++ b/src/test/ui/consts/issue-83182.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-83182.rs:5:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer in `str` | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/issue-83182.rs b/src/test/ui/consts/issue-83182.rs index f714fd6e8f9df..292765843048c 100644 --- a/src/test/ui/consts/issue-83182.rs +++ b/src/test/ui/consts/issue-83182.rs @@ -4,5 +4,5 @@ use std::mem; struct MyStr(str); const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; //~^ ERROR: it is undefined behavior to use this value -//~| type validation failed at .<deref>.0: encountered a pointer in `str` +//~| constructing invalid value at .<deref>.0: encountered a pointer in `str` fn main() {} diff --git a/src/test/ui/consts/issue-96169.rs b/src/test/ui/consts/issue-96169.rs new file mode 100644 index 0000000000000..14c0a1399a00e --- /dev/null +++ b/src/test/ui/consts/issue-96169.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: -Zmir-opt-level=4 --emit=mir +#![allow(unused)] +fn a() -> usize { 0 } + +fn bar(_: u32) {} + +fn baz() -> *const dyn Fn(u32) { unimplemented!() } + +fn foo() { + match () { + _ if baz() == &bar as &dyn Fn(u32) => (), + () => (), + } +} + +fn main() { +} diff --git a/src/test/ui/consts/issue-miri-1910.stderr b/src/test/ui/consts/issue-miri-1910.stderr index 87882449c7342..afcf11bd5f247 100644 --- a/src/test/ui/consts/issue-miri-1910.stderr +++ b/src/test/ui/consts/issue-miri-1910.stderr @@ -1,22 +1,18 @@ error: any use of this value will cause an error --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unable to turn pointer into raw bytes - | inside `std::ptr::read::<u8>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `C` at $DIR/issue-miri-1910.rs:7:5 +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn pointer into raw bytes + | inside `std::ptr::read::<u8>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `C` at $DIR/issue-miri-1910.rs:7:5 | ::: $DIR/issue-miri-1910.rs:4:1 | -LL | / const C: () = unsafe { -LL | | let foo = Some(&42 as *const i32); -LL | | let one_and_a_half_pointers = std::mem::size_of::<*const i32>()/2*3; -LL | | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); -LL | | }; - | |__- +LL | const C: () = unsafe { + | ----------- | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -24,3 +20,24 @@ LL | | }; error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn pointer into raw bytes + | inside `std::ptr::read::<u8>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `C` at $DIR/issue-miri-1910.rs:7:5 + | + ::: $DIR/issue-miri-1910.rs:4:1 + | +LL | const C: () = unsafe { + | ----------- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/miri_unleashed/assoc_const.stderr b/src/test/ui/consts/miri_unleashed/assoc_const.stderr index 193a49bb2666f..1f82ac827ad1d 100644 --- a/src/test/ui/consts/miri_unleashed/assoc_const.stderr +++ b/src/test/ui/consts/miri_unleashed/assoc_const.stderr @@ -15,3 +15,28 @@ LL | const F: u32 = (U::X, 42).1; error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | calling non-const function `<Vec<u32> as Drop>::drop` + | inside `std::ptr::drop_in_place::<Vec<u32>> - shim(Some(Vec<u32>))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `std::ptr::drop_in_place::<(Vec<u32>, u32)> - shim(Some((Vec<u32>, u32)))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `<String as Bar<Vec<u32>, String>>::F` at $DIR/assoc_const.rs:14:31 + | + ::: $DIR/assoc_const.rs:14:5 + | +LL | const F: u32 = (U::X, 42).1; + | ------------ + | +note: the lint level is defined here + --> $DIR/assoc_const.rs:4:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr index e15717979c5cb..cbf02199f5bf5 100644 --- a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr +++ b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr @@ -7,3 +7,18 @@ LL | let y = <String as Bar<String>>::F; error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/assoc_const_2.rs:12:20 + | +LL | const F: u32 = 100 / U::X; + | ------------ ^^^^^^^^^^ attempt to divide `100_u32` by zero + | +note: the lint level is defined here + --> $DIR/assoc_const_2.rs:3:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index c48f59fe84890..fa2088124b0bb 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -47,3 +47,54 @@ LL | const READ_MUT: u32 = unsafe { MUTABLE }; error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static.rs:13:5 + | +LL | const MUTATE_INTERIOR_MUT: usize = { + | -------------------------------- +LL | static FOO: AtomicUsize = AtomicUsize::new(0); +LL | FOO.fetch_add(1, Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `AtomicUsize::fetch_add` + | +note: the lint level is defined here + --> $DIR/const_refers_to_static.rs:3:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static.rs:18:14 + | +LL | const READ_INTERIOR_MUT: usize = { + | ------------------------------ +LL | static FOO: AtomicUsize = AtomicUsize::new(0); +LL | unsafe { *(&FOO as *const _ as *const usize) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | +note: the lint level is defined here + --> $DIR/const_refers_to_static.rs:3:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static.rs:22:32 + | +LL | const READ_MUT: u32 = unsafe { MUTABLE }; + | ------------------- ^^^^^^^ constant accesses static + | +note: the lint level is defined here + --> $DIR/const_refers_to_static.rs:3:10 + | +LL | #![allow(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static2.32bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.32bit.stderr index 039b466ee0780..b3ad81e49bc16 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static2.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.32bit.stderr @@ -1,12 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static2.rs:11:1 | -LL | / const REF_INTERIOR_MUT: &usize = { -LL | | -LL | | static FOO: AtomicUsize = AtomicUsize::new(0); -LL | | unsafe { &*(&FOO as *const _ as *const usize) } -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const REF_INTERIOR_MUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 4, align: 4) { @@ -16,12 +12,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static2.rs:18:1 | -LL | / const READ_IMMUT: &usize = { -LL | | -LL | | static FOO: usize = 0; -LL | | &FOO -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const READ_IMMUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static2.64bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.64bit.stderr index e0e2ec31efbaf..24bd070928265 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static2.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.64bit.stderr @@ -1,12 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static2.rs:11:1 | -LL | / const REF_INTERIOR_MUT: &usize = { -LL | | -LL | | static FOO: AtomicUsize = AtomicUsize::new(0); -LL | | unsafe { &*(&FOO as *const _ as *const usize) } -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const REF_INTERIOR_MUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 8, align: 8) { @@ -16,12 +12,8 @@ LL | | }; error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static2.rs:18:1 | -LL | / const READ_IMMUT: &usize = { -LL | | -LL | | static FOO: usize = 0; -LL | | &FOO -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const READ_IMMUT: &usize = { + | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 8, align: 8) { diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 186c5b1856baa..20a96b57f29b9 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -1,11 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:12:1 | -LL | / const SLICE_MUT: &[u8; 1] = { -LL | | -LL | | unsafe { &static_cross_crate::ZERO } -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const SLICE_MUT: &[u8; 1] = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 4, align: 4) { @@ -21,11 +18,8 @@ LL | SLICE_MUT => true, error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | -LL | / const U8_MUT: &u8 = { -LL | | -LL | | unsafe { &static_cross_crate::ZERO[0] } -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const U8_MUT: &u8 = { + | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 4, align: 4) { @@ -41,14 +35,10 @@ LL | U8_MUT => true, warning: any use of this value will cause an error --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | -LL | / const U8_MUT2: &u8 = { -LL | | unsafe { &(*static_cross_crate::ZERO_REF)[0] } - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static -LL | | -LL | | -LL | | -LL | | }; - | |__- +LL | const U8_MUT2: &u8 = { + | ------------------ +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static | note: the lint level is defined here --> $DIR/const_refers_to_static_cross_crate.rs:23:8 @@ -67,14 +57,10 @@ LL | U8_MUT2 => true, warning: any use of this value will cause an error --> $DIR/const_refers_to_static_cross_crate.rs:32:20 | -LL | / const U8_MUT3: &u8 = { -LL | | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static -LL | | -LL | | -LL | | -LL | | }; - | |__- +LL | const U8_MUT3: &u8 = { + | ------------------ +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static | note: the lint level is defined here --> $DIR/const_refers_to_static_cross_crate.rs:30:8 @@ -170,3 +156,37 @@ LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => error: aborting due to 10 previous errors; 3 warnings emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 + | +LL | const U8_MUT2: &u8 = { + | ------------------ +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | +note: the lint level is defined here + --> $DIR/const_refers_to_static_cross_crate.rs:23:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static_cross_crate.rs:32:20 + | +LL | const U8_MUT3: &u8 = { + | ------------------ +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | +note: the lint level is defined here + --> $DIR/const_refers_to_static_cross_crate.rs:30:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 7a64abd7b9cb8..dfa0f76baa186 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -1,11 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:12:1 | -LL | / const SLICE_MUT: &[u8; 1] = { -LL | | -LL | | unsafe { &static_cross_crate::ZERO } -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const SLICE_MUT: &[u8; 1] = { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 8, align: 8) { @@ -21,11 +18,8 @@ LL | SLICE_MUT => true, error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | -LL | / const U8_MUT: &u8 = { -LL | | -LL | | unsafe { &static_cross_crate::ZERO[0] } -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +LL | const U8_MUT: &u8 = { + | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable | = 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: 8, align: 8) { @@ -41,14 +35,10 @@ LL | U8_MUT => true, warning: any use of this value will cause an error --> $DIR/const_refers_to_static_cross_crate.rs:25:15 | -LL | / const U8_MUT2: &u8 = { -LL | | unsafe { &(*static_cross_crate::ZERO_REF)[0] } - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static -LL | | -LL | | -LL | | -LL | | }; - | |__- +LL | const U8_MUT2: &u8 = { + | ------------------ +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static | note: the lint level is defined here --> $DIR/const_refers_to_static_cross_crate.rs:23:8 @@ -67,14 +57,10 @@ LL | U8_MUT2 => true, warning: any use of this value will cause an error --> $DIR/const_refers_to_static_cross_crate.rs:32:20 | -LL | / const U8_MUT3: &u8 = { -LL | | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static -LL | | -LL | | -LL | | -LL | | }; - | |__- +LL | const U8_MUT3: &u8 = { + | ------------------ +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static | note: the lint level is defined here --> $DIR/const_refers_to_static_cross_crate.rs:30:8 @@ -170,3 +156,37 @@ LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => error: aborting due to 10 previous errors; 3 warnings emitted For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static_cross_crate.rs:25:15 + | +LL | const U8_MUT2: &u8 = { + | ------------------ +LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | +note: the lint level is defined here + --> $DIR/const_refers_to_static_cross_crate.rs:23:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/const_refers_to_static_cross_crate.rs:32:20 + | +LL | const U8_MUT3: &u8 = { + | ------------------ +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | +note: the lint level is defined here + --> $DIR/const_refers_to_static_cross_crate.rs:30:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index 9d1bb2ac91c49..bb8636f1225ad 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -1,10 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:17:1 | -LL | / const MUH: Meh = Meh { -LL | | x: &UnsafeCell::new(42), -LL | | }; - | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const` +LL | const MUH: Meh = Meh { + | ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const` | = 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: 4, align: 4) { @@ -15,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:27:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` | = 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: 8, align: 4) { @@ -26,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:31:1 | LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const` + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` | = 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: 4, align: 4) { diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index fe939c0393189..f1652da922a57 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -1,10 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:17:1 | -LL | / const MUH: Meh = Meh { -LL | | x: &UnsafeCell::new(42), -LL | | }; - | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const` +LL | const MUH: Meh = Meh { + | ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const` | = 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: 8, align: 8) { @@ -15,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:27:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` | = 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: 16, align: 8) { @@ -26,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:31:1 | LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const` + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` | = 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: 8, align: 8) { diff --git a/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr b/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr index b5b5a965295a7..e145f6dd2ef58 100644 --- a/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/raw_mutable_const.stderr @@ -2,7 +2,7 @@ error: untyped pointers are not allowed in constant --> $DIR/raw_mutable_const.rs:7:1 | LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: skipping const checks | diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index 10e368ba13396..db2d421427c3e 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -34,14 +34,14 @@ pub const NOT_MULTIPLE_OF_SIZE: isize = { pub const OFFSET_FROM_NULL: isize = { let ptr = 0 as *const u8; unsafe { ptr_offset_from(ptr, ptr) } //~ERROR evaluation of constant value failed - //~| null pointer is not a valid pointer + //~| null pointer is a dangling pointer }; pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| 0x8 is not a valid pointer + //~| 0x8[noalloc] is a dangling pointer }; const OUT_OF_BOUNDS_1: isize = { diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index eb7f1d7a6b252..94d778bc8a150 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -28,31 +28,31 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:36:14 | LL | unsafe { ptr_offset_from(ptr, ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:43:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8[noalloc] is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:52:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc20 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:61:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc23 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:69:14 | LL | unsafe { ptr_offset_from(end_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc26 has size 4, so pointer at offset 10 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:78:27 diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index 4d3e7ee241110..5a792bba50cb2 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -18,7 +18,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds + | out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:8:43 @@ -32,7 +32,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds + | out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:9:45 @@ -102,7 +102,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds + | out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds | inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:15:49 @@ -116,7 +116,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:17:50 @@ -130,7 +130,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) as *mut T } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: 0x1 is not a valid pointer + | out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | inside `ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:18:42 @@ -144,7 +144,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: null pointer is not a valid pointer + | out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) | inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:21:50 @@ -158,7 +158,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: 0x7f..f is not a valid pointer + | out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance) | inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:24:47 diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr index 12f6ca0b51a53..67b9fec4a0e11 100644 --- a/src/test/ui/consts/ptr_comparisons.stderr +++ b/src/test/ui/consts/ptr_comparisons.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds + | out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/ptr_comparisons.rs:58:34 @@ -22,9 +22,7 @@ error: any use of this value will cause an error --> $DIR/ptr_comparisons.rs:65:27 | LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; - | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | unable to turn pointer into raw bytes + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -34,9 +32,7 @@ error: any use of this value will cause an error --> $DIR/ptr_comparisons.rs:70:27 | LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; - | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------- - | | - | unable to turn pointer into raw bytes + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> @@ -44,3 +40,25 @@ LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ptr_comparisons.rs:65:27 + | +LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + +Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/ptr_comparisons.rs:70:27 + | +LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/qualif-union.rs b/src/test/ui/consts/qualif-union.rs index 2054b5b89ed6e..11c019be96432 100644 --- a/src/test/ui/consts/qualif-union.rs +++ b/src/test/ui/consts/qualif-union.rs @@ -1,18 +1,19 @@ // Checks that unions use type based qualification. Regression test for issue #90268. -#![feature(untagged_unions)] + use std::cell::Cell; +use std::mem::ManuallyDrop; -union U { i: u32, c: Cell<u32> } +union U { i: u32, c: ManuallyDrop<Cell<u32>> } -const C1: Cell<u32> = { - unsafe { U { c: Cell::new(0) }.c } +const C1: ManuallyDrop<Cell<u32>> = { + unsafe { U { c: ManuallyDrop::new(Cell::new(0)) }.c } }; -const C2: Cell<u32> = { +const C2: ManuallyDrop<Cell<u32>> = { unsafe { U { i : 0 }.c } }; -const C3: Cell<u32> = { +const C3: ManuallyDrop<Cell<u32>> = { let mut u = U { i: 0 }; u.i = 1; unsafe { u.c } diff --git a/src/test/ui/consts/qualif-union.stderr b/src/test/ui/consts/qualif-union.stderr index fda8ad4a3bc81..8ec68ada048a5 100644 --- a/src/test/ui/consts/qualif-union.stderr +++ b/src/test/ui/consts/qualif-union.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:27:26 + --> $DIR/qualif-union.rs:28:26 | LL | let _: &'static _ = &C1; | ---------- ^^ creates a temporary which is freed while still in use @@ -10,7 +10,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:28:26 + --> $DIR/qualif-union.rs:29:26 | LL | let _: &'static _ = &C2; | ---------- ^^ creates a temporary which is freed while still in use @@ -21,7 +21,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:29:26 + --> $DIR/qualif-union.rs:30:26 | LL | let _: &'static _ = &C3; | ---------- ^^ creates a temporary which is freed while still in use @@ -32,7 +32,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:30:26 + --> $DIR/qualif-union.rs:31:26 | LL | let _: &'static _ = &C4; | ---------- ^^ creates a temporary which is freed while still in use @@ -43,7 +43,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:31:26 + --> $DIR/qualif-union.rs:32:26 | LL | let _: &'static _ = &C5; | ---------- ^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/consts/raw-ptr-const.stderr b/src/test/ui/consts/raw-ptr-const.stderr index 974b1c3ff45b5..0ebe1e95ca3ef 100644 --- a/src/test/ui/consts/raw-ptr-const.stderr +++ b/src/test/ui/consts/raw-ptr-const.stderr @@ -2,7 +2,7 @@ error: untyped pointers are not allowed in constant --> $DIR/raw-ptr-const.rs:7:1 | LL | const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index 104899f490012..d68960b097213 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -2,7 +2,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index 104899f490012..d68960b097213 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -2,7 +2,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:18 diff --git a/src/test/ui/consts/recursive.stderr b/src/test/ui/consts/recursive.stderr index 31ac1fff4e84e..647ed1db20bdc 100644 --- a/src/test/ui/consts/recursive.stderr +++ b/src/test/ui/consts/recursive.stderr @@ -21,7 +21,7 @@ LL | f(x); | inside `X` at $DIR/recursive.rs:9:15 ... LL | const X: () = f(1); - | ------------------- + | ----------- | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -29,3 +29,22 @@ LL | const X: () = f(1); error: aborting due to previous error; 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/recursive.rs:4:5 + | +LL | f(x); + | ^^^^ + | | + | reached the configured maximum number of stack frames + | inside `f::<i32>` at $DIR/recursive.rs:4:5 + | [... 126 additional calls inside `f::<i32>` at $DIR/recursive.rs:4:5 ...] + | inside `X` at $DIR/recursive.rs:9:15 +... +LL | const X: () = f(1); + | ----------- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/std/alloc.32bit.stderr b/src/test/ui/consts/std/alloc.32bit.stderr index 138eb69971cbb..79efcd3f62eed 100644 --- a/src/test/ui/consts/std/alloc.32bit.stderr +++ b/src/test/ui/consts/std/alloc.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc.rs:9:1 | LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag | = 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: 8, align: 4) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc.rs:13:1 | LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag | = 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: 8, align: 4) { diff --git a/src/test/ui/consts/std/alloc.64bit.stderr b/src/test/ui/consts/std/alloc.64bit.stderr index ecb08c39f3fdd..cb477b72b3121 100644 --- a/src/test/ui/consts/std/alloc.64bit.stderr +++ b/src/test/ui/consts/std/alloc.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc.rs:9:1 | LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag | = 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: 16, align: 8) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc.rs:13:1 | LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/std/cell.stderr b/src/test/ui/consts/std/cell.stderr index 355c326f0b6f1..937fa7db0c8c0 100644 --- a/src/test/ui/consts/std/cell.stderr +++ b/src/test/ui/consts/std/cell.stderr @@ -2,25 +2,25 @@ error: encountered dangling pointer in final constant --> $DIR/cell.rs:6:1 | LL | static FOO: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered dangling pointer in final constant --> $DIR/cell.rs:8:1 | LL | const FOO_CONST: Wrap<*mut u32> = Wrap(Cell::new(42).as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered dangling pointer in final constant --> $DIR/cell.rs:22:1 | LL | const FOO4_CONST: Wrap<*mut u32> = Wrap(FOO3_CONST.0.as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: encountered dangling pointer in final constant --> $DIR/cell.rs:27:1 | LL | const FOO2: *mut u32 = Cell::new(42).as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr index e98eefc11c3c8..d3177784789fc 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -135,7 +135,7 @@ LL | hint_unreachable() | inside `<i32 as Const>::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:13:36 ... LL | const CONSTANT: i32 = unsafe { fake_type() }; - | --------------------------------------------- + | ------------------- | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -150,3 +150,147 @@ LL | dbg!(i32::CONSTANT); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/uninhabited-const-issue-61744.rs:4:5 + | +LL | hint_unreachable() + | ^^^^^^^^^^^^^^^^^^ + | | + | reached the configured maximum number of stack frames + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5 + | inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `<i32 as Const>::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:13:36 +... +LL | const CONSTANT: i32 = unsafe { fake_type() }; + | ------------------- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/consts/validate_never_arrays.32bit.stderr b/src/test/ui/consts/validate_never_arrays.32bit.stderr index 6280a7478e70c..a5dbc718145ca 100644 --- a/src/test/ui/consts/validate_never_arrays.32bit.stderr +++ b/src/test/ui/consts/validate_never_arrays.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:4:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type [!; 1] + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] | = 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: 4, align: 4) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:7:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` | = 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: 8, align: 4) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:8:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` | = 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: 8, align: 4) { diff --git a/src/test/ui/consts/validate_never_arrays.64bit.stderr b/src/test/ui/consts/validate_never_arrays.64bit.stderr index c5a71e5be51b6..dac4e200a89de 100644 --- a/src/test/ui/consts/validate_never_arrays.64bit.stderr +++ b/src/test/ui/consts/validate_never_arrays.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:4:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type [!; 1] + | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] | = 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: 8, align: 8) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:7:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` | = 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: 16, align: 8) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:8:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` + | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` | = 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: 16, align: 8) { diff --git a/src/test/ui/consts/write-to-static-mut-in-static.stderr b/src/test/ui/consts/write-to-static-mut-in-static.stderr index 8d5113cbfd9f5..395b2d42f97a3 100644 --- a/src/test/ui/consts/write-to-static-mut-in-static.stderr +++ b/src/test/ui/consts/write-to-static-mut-in-static.stderr @@ -8,7 +8,7 @@ error[E0391]: cycle detected when const-evaluating + checking `C` --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:34 diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index 79095452f9d02..128087f1e3755 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `Foo` in the current scop --> $DIR/copy-a-resource.rs:18:16 | LL | struct Foo { - | ---------- method `clone` not found for this + | ---------- method `clone` not found for this struct ... LL | let _y = x.clone(); | ^^^^^ method not found in `Foo` diff --git a/src/test/ui/custom_test_frameworks/mismatch.stderr b/src/test/ui/custom_test_frameworks/mismatch.stderr index e848ddc55b7df..61061ae529d12 100644 --- a/src/test/ui/custom_test_frameworks/mismatch.stderr +++ b/src/test/ui/custom_test_frameworks/mismatch.stderr @@ -6,7 +6,7 @@ LL | #[test] LL | fn wrong_kind(){} | ^^^^^^^^^^^^^^^^^ the trait `Testable` is not implemented for `TestDescAndFn` | - = note: required for the cast to the object type `dyn Testable` + = note: required for the cast from `TestDescAndFn` to the object type `dyn Testable` = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr index 60bfbe94a8a8b..cfe1e62d9318f 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr @@ -16,12 +16,6 @@ error: no path from `WillChange` to `trait_def` LL | #[rustc_then_this_would_need(trait_def)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: OK - --> $DIR/dep-graph-struct-signature.rs:32:9 - | -LL | #[rustc_then_this_would_need(fn_sig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: OK --> $DIR/dep-graph-struct-signature.rs:36:5 | @@ -52,36 +46,12 @@ error: OK LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: OK - --> $DIR/dep-graph-struct-signature.rs:48:9 - | -LL | #[rustc_then_this_would_need(fn_sig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: OK - --> $DIR/dep-graph-struct-signature.rs:49:9 - | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: OK --> $DIR/dep-graph-struct-signature.rs:53:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: OK - --> $DIR/dep-graph-struct-signature.rs:55:9 - | -LL | #[rustc_then_this_would_need(fn_sig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: OK - --> $DIR/dep-graph-struct-signature.rs:56:9 - | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: OK --> $DIR/dep-graph-struct-signature.rs:61:9 | @@ -106,12 +76,6 @@ error: no path from `WillChange` to `type_of` LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:77:9 - | -LL | #[rustc_then_this_would_need(fn_sig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:81:5 | @@ -130,5 +94,41 @@ error: no path from `WillChange` to `typeck` LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: OK + --> $DIR/dep-graph-struct-signature.rs:32:9 + | +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: no path from `WillChange` to `fn_sig` + --> $DIR/dep-graph-struct-signature.rs:77:9 + | +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: OK + --> $DIR/dep-graph-struct-signature.rs:48:9 + | +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: OK + --> $DIR/dep-graph-struct-signature.rs:49:9 + | +LL | #[rustc_then_this_would_need(typeck)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: OK + --> $DIR/dep-graph-struct-signature.rs:55:9 + | +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: OK + --> $DIR/dep-graph-struct-signature.rs:56:9 + | +LL | #[rustc_then_this_would_need(typeck)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 22 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.stderr b/src/test/ui/dep-graph/dep-graph-type-alias.stderr index c59cf8014c3d1..42ac803b22ece 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-type-alias.stderr @@ -28,30 +28,12 @@ error: no path from `TypeAlias` to `type_of` LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: OK - --> $DIR/dep-graph-type-alias.rs:36:5 - | -LL | #[rustc_then_this_would_need(fn_sig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: no path from `TypeAlias` to `type_of` --> $DIR/dep-graph-type-alias.rs:42:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: OK - --> $DIR/dep-graph-type-alias.rs:44:5 - | -LL | #[rustc_then_this_would_need(fn_sig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: OK - --> $DIR/dep-graph-type-alias.rs:45:5 - | -LL | #[rustc_then_this_would_need(typeck)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: OK --> $DIR/dep-graph-type-alias.rs:49:1 | @@ -70,5 +52,23 @@ error: OK LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: OK + --> $DIR/dep-graph-type-alias.rs:36:5 + | +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: OK + --> $DIR/dep-graph-type-alias.rs:44:5 + | +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: OK + --> $DIR/dep-graph-type-alias.rs:45:5 + | +LL | #[rustc_then_this_would_need(typeck)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 12 previous errors diff --git a/src/test/ui/deprecation/atomic_initializers.stderr b/src/test/ui/deprecation/atomic_initializers.stderr index eaf5c61b440bd..30fcc9de6181e 100644 --- a/src/test/ui/deprecation/atomic_initializers.stderr +++ b/src/test/ui/deprecation/atomic_initializers.stderr @@ -2,9 +2,13 @@ warning: use of deprecated constant `std::sync::atomic::ATOMIC_ISIZE_INIT`: the --> $DIR/atomic_initializers.rs:8:27 | LL | static FOO: AtomicIsize = ATOMIC_ISIZE_INIT; - | ^^^^^^^^^^^^^^^^^ help: replace the use of the deprecated constant: `AtomicIsize::new(0)` + | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(deprecated)]` on by default +help: replace the use of the deprecated constant + | +LL | static FOO: AtomicIsize = AtomicIsize::new(0); + | ~~~~~~~~~~~~~~~~~~~ warning: 1 warning emitted diff --git a/src/test/ui/deprecation/issue-84637-deprecated-associated-function.stderr b/src/test/ui/deprecation/issue-84637-deprecated-associated-function.stderr index e65d21bb09bbe..8d4529526e370 100644 --- a/src/test/ui/deprecation/issue-84637-deprecated-associated-function.stderr +++ b/src/test/ui/deprecation/issue-84637-deprecated-associated-function.stderr @@ -2,19 +2,28 @@ error: use of deprecated associated function `core::str::<impl str>::trim_left`: --> $DIR/issue-84637-deprecated-associated-function.rs:6:21 | LL | let _foo = str::trim_left(" aoeu"); - | ^^^^^^^^^ help: replace the use of the deprecated associated function: `trim_start` + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/issue-84637-deprecated-associated-function.rs:3:9 | LL | #![deny(deprecated)] | ^^^^^^^^^^ +help: replace the use of the deprecated associated function + | +LL | let _foo = str::trim_start(" aoeu"); + | ~~~~~~~~~~ error: use of deprecated associated function `core::str::<impl str>::trim_left`: superseded by `trim_start` --> $DIR/issue-84637-deprecated-associated-function.rs:8:26 | LL | let _bar = " aoeu".trim_left(); - | ^^^^^^^^^ help: replace the use of the deprecated associated function: `trim_start` + | ^^^^^^^^^ + | +help: replace the use of the deprecated associated function + | +LL | let _bar = " aoeu".trim_start(); + | ~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/deprecation/suggestion.stderr b/src/test/ui/deprecation/suggestion.stderr index 8d1e108345f30..c5f2fc0912514 100644 --- a/src/test/ui/deprecation/suggestion.stderr +++ b/src/test/ui/deprecation/suggestion.stderr @@ -2,19 +2,28 @@ error: use of deprecated function `bar::deprecated`: replaced by `replacement` --> $DIR/suggestion.rs:42:10 | LL | bar::deprecated(); - | ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement` + | ^^^^^^^^^^ | note: the lint level is defined here --> $DIR/suggestion.rs:8:9 | LL | #![deny(deprecated)] | ^^^^^^^^^^ +help: replace the use of the deprecated function + | +LL | bar::replacement(); + | ~~~~~~~~~~~ error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement` --> $DIR/suggestion.rs:40:9 | LL | foo.deprecated(); - | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement` + | ^^^^^^^^^^ + | +help: replace the use of the deprecated associated function + | +LL | foo.replacement(); + | ~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr index 4feaf3ac96185..bd36a25686a30 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.stderr +++ b/src/test/ui/derive-uninhabited-enum-38885.stderr @@ -5,7 +5,7 @@ LL | enum Foo { | --- variant in this enum LL | Bar(u8), LL | Void(Void), - | ^^^^^^^^^^ + | ^^^^ | = note: `-W dead-code` implied by `-W unused` = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis diff --git a/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr index 383e0b4b725db..baf34b46d8b57 100644 --- a/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr +++ b/src/test/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr @@ -5,13 +5,13 @@ LL | pub struct Whatever { | -------- fields in this struct LL | pub field0: (), LL | field1: (), - | ^^^^^^^^^^ + | ^^^^^^ LL | field2: (), - | ^^^^^^^^^^ + | ^^^^^^ LL | field3: (), - | ^^^^^^^^^^ + | ^^^^^^ LL | field4: (), - | ^^^^^^^^^^ + | ^^^^^^ | note: the lint level is defined here --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11 diff --git a/src/test/ui/derives/clone-debug-dead-code.stderr b/src/test/ui/derives/clone-debug-dead-code.stderr index 73a002511884a..38be486e33207 100644 --- a/src/test/ui/derives/clone-debug-dead-code.stderr +++ b/src/test/ui/derives/clone-debug-dead-code.stderr @@ -2,7 +2,7 @@ error: field `f` is never read --> $DIR/clone-debug-dead-code.rs:6:12 | LL | struct A { f: () } - | - ^^^^^ + | - ^ | | | field in this struct | @@ -16,7 +16,7 @@ error: field `f` is never read --> $DIR/clone-debug-dead-code.rs:10:12 | LL | struct B { f: () } - | - ^^^^^ + | - ^ | | | field in this struct | @@ -26,7 +26,7 @@ error: field `f` is never read --> $DIR/clone-debug-dead-code.rs:14:12 | LL | struct C { f: () } - | - ^^^^^ + | - ^ | | | field in this struct | @@ -36,7 +36,7 @@ error: field `f` is never read --> $DIR/clone-debug-dead-code.rs:18:12 | LL | struct D { f: () } - | - ^^^^^ + | - ^ | | | field in this struct | @@ -46,7 +46,7 @@ error: field `f` is never read --> $DIR/clone-debug-dead-code.rs:21:12 | LL | struct E { f: () } - | - ^^^^^ + | - ^ | | | field in this struct diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index 72dd9c153ab0d..c4fddcf5f2468 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -4,11 +4,11 @@ error[E0599]: the method `clone` exists for struct `Bar<NotClone>`, but its trai LL | struct Bar<T: Foo> { | ------------------ | | - | method `clone` not found for this + | method `clone` not found for this struct | doesn't satisfy `Bar<NotClone>: Clone` ... LL | struct NotClone; - | ---------------- doesn't satisfy `NotClone: Clone` + | --------------- doesn't satisfy `NotClone: Clone` ... LL | Bar::<NotClone> { x: 1 }.clone(); | ^^^^^ method cannot be called on `Bar<NotClone>` due to unsatisfied trait bounds diff --git a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr index 19d2425ff23f7..f655600b76004 100644 --- a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr @@ -11,7 +11,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | @@ -31,7 +31,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | diff --git a/src/test/ui/derives/derives-span-PartialEq-enum.stderr b/src/test/ui/derives/derives-span-PartialEq-enum.stderr index 419832817ca18..ce4b00bfbf574 100644 --- a/src/test/ui/derives/derives-span-PartialEq-enum.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-enum.stderr @@ -11,7 +11,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-enum.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | @@ -31,7 +31,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-enum.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | diff --git a/src/test/ui/derives/derives-span-PartialEq-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-struct.stderr index 0000f882542ae..c5c8f255fb3db 100644 --- a/src/test/ui/derives/derives-span-PartialEq-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-struct.stderr @@ -11,7 +11,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-struct.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | @@ -31,7 +31,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-struct.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | diff --git a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr index 07fa900a8c829..f5d609cb33fe6 100644 --- a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr @@ -11,7 +11,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | @@ -31,7 +31,7 @@ note: an implementation of `PartialEq<_>` might be missing for `Error` --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 | LL | struct Error; - | ^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Error` with `#[derive(PartialEq)]` | diff --git a/src/test/ui/derives/deriving-meta-unknown-trait.stderr b/src/test/ui/derives/deriving-meta-unknown-trait.stderr index bfb673f86f418..f3ff95a85da1a 100644 --- a/src/test/ui/derives/deriving-meta-unknown-trait.stderr +++ b/src/test/ui/derives/deriving-meta-unknown-trait.stderr @@ -7,7 +7,7 @@ LL | #[derive(Eqr)] ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub macro Eq($item:item) { - | ------------------------ similarly named derive macro `Eq` defined here + | ------------ similarly named derive macro `Eq` defined here error: cannot find derive macro `Eqr` in this scope --> $DIR/deriving-meta-unknown-trait.rs:1:10 @@ -18,7 +18,7 @@ LL | #[derive(Eqr)] ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub macro Eq($item:item) { - | ------------------------ similarly named derive macro `Eq` defined here + | ------------ similarly named derive macro `Eq` defined here error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr index 451058cd0ee01..7875f07235661 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr @@ -11,7 +11,7 @@ note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq` --> $DIR/deriving-no-inner-impl-error-message.rs:1:1 | LL | struct NoCloneOrEq; - | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` | @@ -31,7 +31,7 @@ note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq` --> $DIR/deriving-no-inner-impl-error-message.rs:1:1 | LL | struct NoCloneOrEq; - | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` | diff --git a/src/test/ui/derives/issue-91492.stderr b/src/test/ui/derives/issue-91492.stderr index 73c91154a7bda..fbd48336d9126 100644 --- a/src/test/ui/derives/issue-91492.stderr +++ b/src/test/ui/derives/issue-91492.stderr @@ -2,7 +2,7 @@ error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut --> $DIR/issue-91492.rs:4:9 | LL | pub struct NoDerives; - | --------------------- doesn't satisfy `NoDerives: Clone` + | -------------------- doesn't satisfy `NoDerives: Clone` LL | fn fun1(foo: &mut Vec<NoDerives>, bar: &[NoDerives]) { LL | foo.extend_from_slice(bar); | ^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ error[E0599]: the method `extend_from_slice` exists for mutable reference `&mut --> $DIR/issue-91492.rs:12:9 | LL | pub struct SomeDerives; - | ----------------------- doesn't satisfy `SomeDerives: Clone` + | ---------------------- doesn't satisfy `SomeDerives: Clone` LL | fn fun2(foo: &mut Vec<SomeDerives>, bar: &[SomeDerives]) { LL | foo.extend_from_slice(bar); | ^^^^^^^^^^^^^^^^^ @@ -34,10 +34,10 @@ error[E0599]: the method `use_clone` exists for struct `Object<NoDerives, SomeDe --> $DIR/issue-91492.rs:22:9 | LL | pub struct NoDerives; - | --------------------- doesn't satisfy `NoDerives: Clone` + | -------------------- doesn't satisfy `NoDerives: Clone` ... LL | struct Object<T, A>(T, A); - | -------------------------- method `use_clone` not found for this + | ------------------- method `use_clone` not found for this struct ... LL | foo.use_clone(); | ^^^^^^^^^ method cannot be called on `Object<NoDerives, SomeDerives>` due to unsatisfied trait bounds diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr index c94d566f5df22..12be269565da1 100644 --- a/src/test/ui/derives/issue-91550.stderr +++ b/src/test/ui/derives/issue-91550.stderr @@ -2,7 +2,7 @@ error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its tr --> $DIR/issue-91550.rs:8:8 | LL | struct Value(u32); - | ------------------ + | ------------ | | | doesn't satisfy `Value: Eq` | doesn't satisfy `Value: Hash` @@ -22,10 +22,10 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | --------------------- doesn't satisfy `NoDerives: Eq` + | -------------------- doesn't satisfy `NoDerives: Eq` LL | LL | struct Object<T>(T); - | -------------------- method `use_eq` not found for this + | ---------------- method `use_eq` not found for this struct ... LL | foo.use_eq(); | ^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds @@ -41,10 +41,10 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | --------------------- doesn't satisfy `NoDerives: Ord` + | -------------------- doesn't satisfy `NoDerives: Ord` LL | LL | struct Object<T>(T); - | -------------------- method `use_ord` not found for this + | ---------------- method `use_ord` not found for this struct ... LL | foo.use_ord(); | ^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds @@ -60,13 +60,13 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD --> $DIR/issue-91550.rs:28:9 | LL | pub struct NoDerives; - | --------------------- + | -------------------- | | | doesn't satisfy `NoDerives: Ord` | doesn't satisfy `NoDerives: PartialOrd` LL | LL | struct Object<T>(T); - | -------------------- method `use_ord_and_partial_ord` not found for this + | ---------------- method `use_ord_and_partial_ord` not found for this struct ... LL | foo.use_ord_and_partial_ord(); | ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds diff --git a/src/test/ui/deriving/deriving-all-codegen.rs b/src/test/ui/deriving/deriving-all-codegen.rs new file mode 100644 index 0000000000000..aef79ae8a5b8d --- /dev/null +++ b/src/test/ui/deriving/deriving-all-codegen.rs @@ -0,0 +1,106 @@ +// check-pass +// compile-flags: -Zunpretty=expanded +// edition:2021 +// +// This test checks the code generated for all[*] the builtin derivable traits +// on a variety of structs and enums. It protects against accidental changes to +// the generated code, and makes deliberate changes to the generated code +// easier to review. +// +// [*] It excludes `Copy` in some cases, because that changes the code +// generated for `Clone`. +// +// [*] It excludes `RustcEncodable` and `RustDecodable`, which are obsolete and +// also require the `rustc_serialize` crate. + +#![crate_type = "lib"] +#![allow(dead_code)] +#![allow(deprecated)] + +// Empty struct. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Empty; + +// A basic struct. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Point { + x: u32, + y: u32, +} + +// A large struct. +#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Big { + b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32, +} + +// A struct with an unsized field. Some derives are not usable in this case. +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct Unsized([u32]); + +// A packed tuple struct that impls `Copy`. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(packed)] +struct PackedCopy(u32); + +// A packed tuple struct that does not impl `Copy`. Note that the alignment of +// the field must be 1 for this code to be valid. Otherwise it triggers an +// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not +// derive Copy (error E0133)" at MIR building time. This is a weird case and +// it's possible that this struct is not supposed to work, but for now it does. +#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(packed)] +struct PackedNonCopy(u8); + +// An empty enum. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Enum0 {} + +// A single-variant enum. +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Enum1 { + Single { x: u32 } +} + +// A C-like, fieldless enum with a single variant. +#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Fieldless1 { + #[default] + A, +} + +// A C-like, fieldless enum. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Fieldless { + #[default] + A, + B, + C, +} + +// An enum with multiple fieldless and fielded variants. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Mixed { + #[default] + P, + Q, + R(u32), + S { d1: u32, d2: u32 }, +} + +// An enum with no fieldless variants. Note that `Default` cannot be derived +// for this enum. +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Fielded { + X(u32), + Y(bool), + Z(Option<i32>), +} + +// A union. Most builtin traits are not derivable for unions. +#[derive(Clone, Copy)] +pub union Union { + pub b: bool, + pub u: u32, + pub i: i32, +} diff --git a/src/test/ui/deriving/deriving-all-codegen.stdout b/src/test/ui/deriving/deriving-all-codegen.stdout new file mode 100644 index 0000000000000..542911537be7e --- /dev/null +++ b/src/test/ui/deriving/deriving-all-codegen.stdout @@ -0,0 +1,1212 @@ +#![feature(prelude_import)] +// check-pass +// compile-flags: -Zunpretty=expanded +// edition:2021 +// +// This test checks the code generated for all[*] the builtin derivable traits +// on a variety of structs and enums. It protects against accidental changes to +// the generated code, and makes deliberate changes to the generated code +// easier to review. +// +// [*] It excludes `Copy` in some cases, because that changes the code +// generated for `Clone`. +// +// [*] It excludes `RustcEncodable` and `RustDecodable`, which are obsolete and +// also require the `rustc_serialize` crate. + +#![crate_type = "lib"] +#![allow(dead_code)] +#![allow(deprecated)] +#[prelude_import] +use std::prelude::rust_2021::*; +#[macro_use] +extern crate std; + +// Empty struct. +struct Empty; +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Empty { + #[inline] + fn clone(&self) -> Empty { *self } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for Empty { } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Empty { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "Empty") + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for Empty { + #[inline] + fn default() -> Empty { Empty {} } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Empty { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {} +} +impl ::core::marker::StructuralPartialEq for Empty {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Empty { + #[inline] + fn eq(&self, other: &Empty) -> bool { true } +} +impl ::core::marker::StructuralEq for Empty {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Empty { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () {} +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Empty { + #[inline] + fn partial_cmp(&self, other: &Empty) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Empty { + #[inline] + fn cmp(&self, other: &Empty) -> ::core::cmp::Ordering { + ::core::cmp::Ordering::Equal + } +} + +// A basic struct. +struct Point { + x: u32, + y: u32, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Point { + #[inline] + fn clone(&self) -> Point { + let _: ::core::clone::AssertParamIsClone<u32>; + *self + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for Point { } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Point { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x", + &&self.x, "y", &&self.y) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for Point { + #[inline] + fn default() -> Point { + Point { + x: ::core::default::Default::default(), + y: ::core::default::Default::default(), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Point { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.x, state); + ::core::hash::Hash::hash(&self.y, state) + } +} +impl ::core::marker::StructuralPartialEq for Point {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Point { + #[inline] + fn eq(&self, other: &Point) -> bool { + self.x == other.x && self.y == other.y + } + #[inline] + fn ne(&self, other: &Point) -> bool { + self.x != other.x || self.y != other.y + } +} +impl ::core::marker::StructuralEq for Point {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Point { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Point { + #[inline] + fn partial_cmp(&self, other: &Point) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y), + cmp => cmp, + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Point { + #[inline] + fn cmp(&self, other: &Point) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&self.x, &other.x) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&self.y, &other.y), + cmp => cmp, + } + } +} + +// A large struct. +struct Big { + b1: u32, + b2: u32, + b3: u32, + b4: u32, + b5: u32, + b6: u32, + b7: u32, + b8: u32, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Big { + #[inline] + fn clone(&self) -> Big { + Big { + b1: ::core::clone::Clone::clone(&self.b1), + b2: ::core::clone::Clone::clone(&self.b2), + b3: ::core::clone::Clone::clone(&self.b3), + b4: ::core::clone::Clone::clone(&self.b4), + b5: ::core::clone::Clone::clone(&self.b5), + b6: ::core::clone::Clone::clone(&self.b6), + b7: ::core::clone::Clone::clone(&self.b7), + b8: ::core::clone::Clone::clone(&self.b8), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Big { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + let names: &'static _ = + &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"]; + let values: &[&dyn ::core::fmt::Debug] = + &[&&self.b1, &&self.b2, &&self.b3, &&self.b4, &&self.b5, + &&self.b6, &&self.b7, &&self.b8]; + ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big", names, + values) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for Big { + #[inline] + fn default() -> Big { + Big { + b1: ::core::default::Default::default(), + b2: ::core::default::Default::default(), + b3: ::core::default::Default::default(), + b4: ::core::default::Default::default(), + b5: ::core::default::Default::default(), + b6: ::core::default::Default::default(), + b7: ::core::default::Default::default(), + b8: ::core::default::Default::default(), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Big { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.b1, state); + ::core::hash::Hash::hash(&self.b2, state); + ::core::hash::Hash::hash(&self.b3, state); + ::core::hash::Hash::hash(&self.b4, state); + ::core::hash::Hash::hash(&self.b5, state); + ::core::hash::Hash::hash(&self.b6, state); + ::core::hash::Hash::hash(&self.b7, state); + ::core::hash::Hash::hash(&self.b8, state) + } +} +impl ::core::marker::StructuralPartialEq for Big {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Big { + #[inline] + fn eq(&self, other: &Big) -> bool { + self.b1 == other.b1 && self.b2 == other.b2 && self.b3 == other.b3 && + self.b4 == other.b4 && self.b5 == other.b5 && + self.b6 == other.b6 && self.b7 == other.b7 && + self.b8 == other.b8 + } + #[inline] + fn ne(&self, other: &Big) -> bool { + self.b1 != other.b1 || self.b2 != other.b2 || self.b3 != other.b3 || + self.b4 != other.b4 || self.b5 != other.b5 || + self.b6 != other.b6 || self.b7 != other.b7 || + self.b8 != other.b8 + } +} +impl ::core::marker::StructuralEq for Big {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Big { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Big { + #[inline] + fn partial_cmp(&self, other: &Big) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&self.b2, + &other.b2) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b3, + &other.b3) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b4, + &other.b4) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b5, + &other.b5) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b6, + &other.b6) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.b7, + &other.b7) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + ::core::cmp::PartialOrd::partial_cmp(&self.b8, &other.b8), + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Big { + #[inline] + fn cmp(&self, other: &Big) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&self.b1, &other.b1) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.b2, &other.b2) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.b3, &other.b3) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.b4, &other.b4) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.b5, &other.b5) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.b6, &other.b6) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.b7, &other.b7) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&self.b8, &other.b8), + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + } + } +} + +// A struct with an unsized field. Some derives are not usable in this case. +struct Unsized([u32]); +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Unsized { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unsized", + &&self.0) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Unsized { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.0, state) + } +} +impl ::core::marker::StructuralPartialEq for Unsized {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Unsized { + #[inline] + fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 } + #[inline] + fn ne(&self, other: &Unsized) -> bool { self.0 != other.0 } +} +impl ::core::marker::StructuralEq for Unsized {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Unsized { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<[u32]>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Unsized { + #[inline] + fn partial_cmp(&self, other: &Unsized) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Unsized { + #[inline] + fn cmp(&self, other: &Unsized) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&self.0, &other.0) + } +} + +// A packed tuple struct that impls `Copy`. +#[repr(packed)] +struct PackedCopy(u32); +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for PackedCopy { + #[inline] + fn clone(&self) -> PackedCopy { + let _: ::core::clone::AssertParamIsClone<u32>; + *self + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for PackedCopy { } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for PackedCopy { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy", + &&{ self.0 }) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for PackedCopy { + #[inline] + fn default() -> PackedCopy { + PackedCopy(::core::default::Default::default()) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for PackedCopy { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&{ self.0 }, state) + } +} +impl ::core::marker::StructuralPartialEq for PackedCopy {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for PackedCopy { + #[inline] + fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } } + #[inline] + fn ne(&self, other: &PackedCopy) -> bool { { self.0 } != { other.0 } } +} +impl ::core::marker::StructuralEq for PackedCopy {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for PackedCopy { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for PackedCopy { + #[inline] + fn partial_cmp(&self, other: &PackedCopy) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for PackedCopy { + #[inline] + fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) + } +} + +// A packed tuple struct that does not impl `Copy`. Note that the alignment of +// the field must be 1 for this code to be valid. Otherwise it triggers an +// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not +// derive Copy (error E0133)" at MIR building time. This is a weird case and +// it's possible that this struct is not supposed to work, but for now it does. +#[repr(packed)] +struct PackedNonCopy(u8); +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for PackedNonCopy { + #[inline] + fn clone(&self) -> PackedNonCopy { + let Self(ref __self_0_0) = *self; + PackedNonCopy(::core::clone::Clone::clone(__self_0_0)) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for PackedNonCopy { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + let Self(ref __self_0_0) = *self; + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy", + &__self_0_0) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for PackedNonCopy { + #[inline] + fn default() -> PackedNonCopy { + PackedNonCopy(::core::default::Default::default()) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for PackedNonCopy { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let Self(ref __self_0_0) = *self; + ::core::hash::Hash::hash(__self_0_0, state) + } +} +impl ::core::marker::StructuralPartialEq for PackedNonCopy {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for PackedNonCopy { + #[inline] + fn eq(&self, other: &PackedNonCopy) -> bool { + let Self(ref __self_0_0) = *self; + let Self(ref __self_1_0) = *other; + *__self_0_0 == *__self_1_0 + } + #[inline] + fn ne(&self, other: &PackedNonCopy) -> bool { + let Self(ref __self_0_0) = *self; + let Self(ref __self_1_0) = *other; + *__self_0_0 != *__self_1_0 + } +} +impl ::core::marker::StructuralEq for PackedNonCopy {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for PackedNonCopy { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u8>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for PackedNonCopy { + #[inline] + fn partial_cmp(&self, other: &PackedNonCopy) + -> ::core::option::Option<::core::cmp::Ordering> { + let Self(ref __self_0_0) = *self; + let Self(ref __self_1_0) = *other; + ::core::cmp::PartialOrd::partial_cmp(__self_0_0, __self_1_0) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for PackedNonCopy { + #[inline] + fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering { + let Self(ref __self_0_0) = *self; + let Self(ref __self_1_0) = *other; + ::core::cmp::Ord::cmp(__self_0_0, __self_1_0) + } +} + +// An empty enum. +enum Enum0 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Enum0 { + #[inline] + fn clone(&self) -> Enum0 { *self } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for Enum0 { } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Enum0 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + unsafe { ::core::intrinsics::unreachable() } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Enum0 { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + unsafe { ::core::intrinsics::unreachable() } + } +} +impl ::core::marker::StructuralPartialEq for Enum0 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Enum0 { + #[inline] + fn eq(&self, other: &Enum0) -> bool { + unsafe { ::core::intrinsics::unreachable() } + } +} +impl ::core::marker::StructuralEq for Enum0 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Enum0 { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () {} +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Enum0 { + #[inline] + fn partial_cmp(&self, other: &Enum0) + -> ::core::option::Option<::core::cmp::Ordering> { + unsafe { ::core::intrinsics::unreachable() } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Enum0 { + #[inline] + fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering { + unsafe { ::core::intrinsics::unreachable() } + } +} + +// A single-variant enum. +enum Enum1 { + Single { + x: u32, + }, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Enum1 { + #[inline] + fn clone(&self) -> Enum1 { + match self { + Enum1::Single { x: __self_0 } => + Enum1::Single { x: ::core::clone::Clone::clone(__self_0) }, + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Enum1 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + Enum1::Single { x: __self_0 } => + ::core::fmt::Formatter::debug_struct_field1_finish(f, + "Single", "x", &__self_0), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Enum1 { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + match self { + Enum1::Single { x: __self_0 } => + ::core::hash::Hash::hash(__self_0, state), + } + } +} +impl ::core::marker::StructuralPartialEq for Enum1 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Enum1 { + #[inline] + fn eq(&self, other: &Enum1) -> bool { + match (self, other) { + (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) => + *__self_0 == *__arg1_0, + } + } + #[inline] + fn ne(&self, other: &Enum1) -> bool { + match (self, other) { + (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) => + *__self_0 != *__arg1_0, + } + } +} +impl ::core::marker::StructuralEq for Enum1 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Enum1 { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Enum1 { + #[inline] + fn partial_cmp(&self, other: &Enum1) + -> ::core::option::Option<::core::cmp::Ordering> { + match (self, other) { + (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Enum1 { + #[inline] + fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering { + match (self, other) { + (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + } + } +} + +// A C-like, fieldless enum with a single variant. +enum Fieldless1 { + + #[default] + A, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Fieldless1 { + #[inline] + fn clone(&self) -> Fieldless1 { Fieldless1::A } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Fieldless1 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::write_str(f, "A") + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for Fieldless1 { + #[inline] + fn default() -> Fieldless1 { Self::A } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Fieldless1 { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {} +} +impl ::core::marker::StructuralPartialEq for Fieldless1 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Fieldless1 { + #[inline] + fn eq(&self, other: &Fieldless1) -> bool { true } +} +impl ::core::marker::StructuralEq for Fieldless1 {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Fieldless1 { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () {} +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Fieldless1 { + #[inline] + fn partial_cmp(&self, other: &Fieldless1) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Fieldless1 { + #[inline] + fn cmp(&self, other: &Fieldless1) -> ::core::cmp::Ordering { + ::core::cmp::Ordering::Equal + } +} + +// A C-like, fieldless enum. +enum Fieldless { + + #[default] + A, + B, + C, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Fieldless { + #[inline] + fn clone(&self) -> Fieldless { *self } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for Fieldless { } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Fieldless { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"), + Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"), + Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for Fieldless { + #[inline] + fn default() -> Fieldless { Self::A } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Fieldless { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let __self_tag = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_tag, state) + } +} +impl ::core::marker::StructuralPartialEq for Fieldless {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Fieldless { + #[inline] + fn eq(&self, other: &Fieldless) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag == __arg1_tag + } +} +impl ::core::marker::StructuralEq for Fieldless {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Fieldless { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () {} +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Fieldless { + #[inline] + fn partial_cmp(&self, other: &Fieldless) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Fieldless { + #[inline] + fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) + } +} + +// An enum with multiple fieldless and fielded variants. +enum Mixed { + + #[default] + P, + Q, + R(u32), + S { + d1: u32, + d2: u32, + }, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Mixed { + #[inline] + fn clone(&self) -> Mixed { + let _: ::core::clone::AssertParamIsClone<u32>; + *self + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for Mixed { } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Mixed { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + Mixed::P => ::core::fmt::Formatter::write_str(f, "P"), + Mixed::Q => ::core::fmt::Formatter::write_str(f, "Q"), + Mixed::R(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "R", + &__self_0), + Mixed::S { d1: __self_0, d2: __self_1 } => + ::core::fmt::Formatter::debug_struct_field2_finish(f, "S", + "d1", &__self_0, "d2", &__self_1), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::default::Default for Mixed { + #[inline] + fn default() -> Mixed { Self::P } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Mixed { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let __self_tag = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_tag, state); + match self { + Mixed::R(__self_0) => ::core::hash::Hash::hash(__self_0, state), + Mixed::S { d1: __self_0, d2: __self_1 } => { + ::core::hash::Hash::hash(__self_0, state); + ::core::hash::Hash::hash(__self_1, state) + } + _ => {} + } + } +} +impl ::core::marker::StructuralPartialEq for Mixed {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Mixed { + #[inline] + fn eq(&self, other: &Mixed) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag == __arg1_tag && + match (self, other) { + (Mixed::R(__self_0), Mixed::R(__arg1_0)) => + *__self_0 == *__arg1_0, + (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { + d1: __arg1_0, d2: __arg1_1 }) => + *__self_0 == *__arg1_0 && *__self_1 == *__arg1_1, + _ => true, + } + } + #[inline] + fn ne(&self, other: &Mixed) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag != __arg1_tag || + match (self, other) { + (Mixed::R(__self_0), Mixed::R(__arg1_0)) => + *__self_0 != *__arg1_0, + (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { + d1: __arg1_0, d2: __arg1_1 }) => + *__self_0 != *__arg1_0 || *__self_1 != *__arg1_1, + _ => false, + } + } +} +impl ::core::marker::StructuralEq for Mixed {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Mixed { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Mixed { + #[inline] + fn partial_cmp(&self, other: &Mixed) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match (self, other) { + (Mixed::R(__self_0), Mixed::R(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { + d1: __arg1_0, d2: __arg1_1 }) => + match ::core::cmp::PartialOrd::partial_cmp(__self_0, + __arg1_0) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => ::core::cmp::PartialOrd::partial_cmp(__self_1, __arg1_1), + cmp => cmp, + }, + _ => + ::core::option::Option::Some(::core::cmp::Ordering::Equal), + }, + cmp => cmp, + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Mixed { + #[inline] + fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + ::core::cmp::Ordering::Equal => + match (self, other) { + (Mixed::R(__self_0), Mixed::R(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { + d1: __arg1_0, d2: __arg1_1 }) => + match ::core::cmp::Ord::cmp(__self_0, __arg1_0) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(__self_1, __arg1_1), + cmp => cmp, + }, + _ => ::core::cmp::Ordering::Equal, + }, + cmp => cmp, + } + } +} + +// An enum with no fieldless variants. Note that `Default` cannot be derived +// for this enum. +enum Fielded { X(u32), Y(bool), Z(Option<i32>), } +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Fielded { + #[inline] + fn clone(&self) -> Fielded { + match self { + Fielded::X(__self_0) => + Fielded::X(::core::clone::Clone::clone(__self_0)), + Fielded::Y(__self_0) => + Fielded::Y(::core::clone::Clone::clone(__self_0)), + Fielded::Z(__self_0) => + Fielded::Z(::core::clone::Clone::clone(__self_0)), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::fmt::Debug for Fielded { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + Fielded::X(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "X", + &__self_0), + Fielded::Y(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Y", + &__self_0), + Fielded::Z(__self_0) => + ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Z", + &__self_0), + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::hash::Hash for Fielded { + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + let __self_tag = ::core::intrinsics::discriminant_value(self); + ::core::hash::Hash::hash(&__self_tag, state); + match self { + Fielded::X(__self_0) => ::core::hash::Hash::hash(__self_0, state), + Fielded::Y(__self_0) => ::core::hash::Hash::hash(__self_0, state), + Fielded::Z(__self_0) => ::core::hash::Hash::hash(__self_0, state), + } + } +} +impl ::core::marker::StructuralPartialEq for Fielded {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Fielded { + #[inline] + fn eq(&self, other: &Fielded) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag == __arg1_tag && + match (self, other) { + (Fielded::X(__self_0), Fielded::X(__arg1_0)) => + *__self_0 == *__arg1_0, + (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => + *__self_0 == *__arg1_0, + (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => + *__self_0 == *__arg1_0, + _ => unsafe { ::core::intrinsics::unreachable() } + } + } + #[inline] + fn ne(&self, other: &Fielded) -> bool { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + __self_tag != __arg1_tag || + match (self, other) { + (Fielded::X(__self_0), Fielded::X(__arg1_0)) => + *__self_0 != *__arg1_0, + (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => + *__self_0 != *__arg1_0, + (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => + *__self_0 != *__arg1_0, + _ => unsafe { ::core::intrinsics::unreachable() } + } + } +} +impl ::core::marker::StructuralEq for Fielded {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Fielded { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq<u32>; + let _: ::core::cmp::AssertParamIsEq<bool>; + let _: ::core::cmp::AssertParamIsEq<Option<i32>>; + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialOrd for Fielded { + #[inline] + fn partial_cmp(&self, other: &Fielded) + -> ::core::option::Option<::core::cmp::Ordering> { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match (self, other) { + (Fielded::X(__self_0), Fielded::X(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => + ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0), + _ => unsafe { ::core::intrinsics::unreachable() } + }, + cmp => cmp, + } + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Ord for Fielded { + #[inline] + fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering { + let __self_tag = ::core::intrinsics::discriminant_value(self); + let __arg1_tag = ::core::intrinsics::discriminant_value(other); + match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) { + ::core::cmp::Ordering::Equal => + match (self, other) { + (Fielded::X(__self_0), Fielded::X(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => + ::core::cmp::Ord::cmp(__self_0, __arg1_0), + _ => unsafe { ::core::intrinsics::unreachable() } + }, + cmp => cmp, + } + } +} + +// A union. Most builtin traits are not derivable for unions. +pub union Union { + pub b: bool, + pub u: u32, + pub i: i32, +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::clone::Clone for Union { + #[inline] + fn clone(&self) -> Union { + let _: ::core::clone::AssertParamIsCopy<Self>; + *self + } +} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::marker::Copy for Union { } diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr index 3e2282743bfce..e45344aa51fc3 100644 --- a/src/test/ui/destructuring-assignment/note-unsupported.stderr +++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr @@ -52,14 +52,8 @@ LL | struct S { x: u8, y: u8 } note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait AddAssign<Rhs = Self> { -LL | | /// Performs the `+=` operation. -LL | | /// -LL | | /// # Example -... | -LL | | fn add_assign(&mut self, rhs: Rhs); -LL | | } - | |_^ +LL | pub trait AddAssign<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:17:22 diff --git a/src/test/ui/diagnostic-width/flag-human.rs b/src/test/ui/diagnostic-width/flag-human.rs new file mode 100644 index 0000000000000..289bfbabd949b --- /dev/null +++ b/src/test/ui/diagnostic-width/flag-human.rs @@ -0,0 +1,9 @@ +// compile-flags: --diagnostic-width=20 + +// This test checks that `-Z output-width` effects the human error output by restricting it to an +// arbitrarily low value so that the effect is visible. + +fn main() { + let _: () = 42; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/flag-human.stderr b/src/test/ui/diagnostic-width/flag-human.stderr similarity index 100% rename from src/test/ui/terminal-width/flag-human.stderr rename to src/test/ui/diagnostic-width/flag-human.stderr diff --git a/src/test/ui/diagnostic-width/flag-json.rs b/src/test/ui/diagnostic-width/flag-json.rs new file mode 100644 index 0000000000000..51a1fb447c7d2 --- /dev/null +++ b/src/test/ui/diagnostic-width/flag-json.rs @@ -0,0 +1,9 @@ +// compile-flags: --diagnostic-width=20 --error-format=json + +// This test checks that `-Z output-width` effects the JSON error output by restricting it to an +// arbitrarily low value so that the effect is visible. + +fn main() { + let _: () = 42; + //~^ ERROR arguments to this function are incorrect +} diff --git a/src/test/ui/terminal-width/flag-json.stderr b/src/test/ui/diagnostic-width/flag-json.stderr similarity index 93% rename from src/test/ui/terminal-width/flag-json.stderr rename to src/test/ui/diagnostic-width/flag-json.stderr index 93c246cb3f501..b21391d1640ef 100644 --- a/src/test/ui/terminal-width/flag-json.stderr +++ b/src/test/ui/diagnostic-width/flag-json.stderr @@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":243,"byte_end":245,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":238,"byte_end":240,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types --> $DIR/flag-json.rs:7:17 | LL | ..._: () = 42; diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs b/src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs similarity index 100% rename from src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs rename to src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr b/src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr similarity index 100% rename from src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr rename to src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/diagnostic-width/non-whitespace-trimming-2.rs similarity index 100% rename from src/test/ui/terminal-width/non-whitespace-trimming-2.rs rename to src/test/ui/diagnostic-width/non-whitespace-trimming-2.rs diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr b/src/test/ui/diagnostic-width/non-whitespace-trimming-2.stderr similarity index 100% rename from src/test/ui/terminal-width/non-whitespace-trimming-2.stderr rename to src/test/ui/diagnostic-width/non-whitespace-trimming-2.stderr diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs b/src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.rs similarity index 100% rename from src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs rename to src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.rs diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr b/src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr similarity index 100% rename from src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr rename to src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.rs b/src/test/ui/diagnostic-width/non-whitespace-trimming.rs similarity index 100% rename from src/test/ui/terminal-width/non-whitespace-trimming.rs rename to src/test/ui/diagnostic-width/non-whitespace-trimming.rs diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.stderr b/src/test/ui/diagnostic-width/non-whitespace-trimming.stderr similarity index 100% rename from src/test/ui/terminal-width/non-whitespace-trimming.stderr rename to src/test/ui/diagnostic-width/non-whitespace-trimming.stderr diff --git a/src/test/ui/terminal-width/tabs-trimming.rs b/src/test/ui/diagnostic-width/tabs-trimming.rs similarity index 100% rename from src/test/ui/terminal-width/tabs-trimming.rs rename to src/test/ui/diagnostic-width/tabs-trimming.rs diff --git a/src/test/ui/terminal-width/tabs-trimming.stderr b/src/test/ui/diagnostic-width/tabs-trimming.stderr similarity index 100% rename from src/test/ui/terminal-width/tabs-trimming.stderr rename to src/test/ui/diagnostic-width/tabs-trimming.stderr diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.rs b/src/test/ui/diagnostic-width/whitespace-trimming-2.rs similarity index 100% rename from src/test/ui/terminal-width/whitespace-trimming-2.rs rename to src/test/ui/diagnostic-width/whitespace-trimming-2.rs diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.stderr b/src/test/ui/diagnostic-width/whitespace-trimming-2.stderr similarity index 100% rename from src/test/ui/terminal-width/whitespace-trimming-2.stderr rename to src/test/ui/diagnostic-width/whitespace-trimming-2.stderr diff --git a/src/test/ui/terminal-width/whitespace-trimming.rs b/src/test/ui/diagnostic-width/whitespace-trimming.rs similarity index 100% rename from src/test/ui/terminal-width/whitespace-trimming.rs rename to src/test/ui/diagnostic-width/whitespace-trimming.rs diff --git a/src/test/ui/terminal-width/whitespace-trimming.stderr b/src/test/ui/diagnostic-width/whitespace-trimming.stderr similarity index 100% rename from src/test/ui/terminal-width/whitespace-trimming.stderr rename to src/test/ui/diagnostic-width/whitespace-trimming.stderr diff --git a/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr b/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr index a4c77e08efe19..473468af6eef8 100644 --- a/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr +++ b/src/test/ui/did_you_mean/compatible-variants-in-pat.stderr @@ -15,7 +15,7 @@ error[E0308]: mismatched types --> $DIR/compatible-variants-in-pat.rs:21:9 | LL | struct S; - | --------- unit struct defined here + | -------- unit struct defined here ... LL | match s { | - this expression has type `Option<S>` @@ -40,7 +40,7 @@ error[E0308]: mismatched types --> $DIR/compatible-variants-in-pat.rs:32:9 | LL | struct S; - | --------- unit struct defined here + | -------- unit struct defined here ... LL | match s { | - this expression has type `Result<S, S>` diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index d5e16e1ff273d..bdbfa4dd7136b 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -88,7 +88,7 @@ error[E0599]: no method named `hello_method` found for struct `S` in the current --> $DIR/issue-40006.rs:38:7 | LL | struct S; - | --------- method `hello_method` not found for this + | -------- method `hello_method` not found for this struct ... LL | S.hello_method(); | ^^^^^^^^^^^^ method not found in `S` diff --git a/src/test/ui/dont-suggest-private-trait-method.stderr b/src/test/ui/dont-suggest-private-trait-method.stderr index fd7fdb4f7226c..1492670dc6335 100644 --- a/src/test/ui/dont-suggest-private-trait-method.stderr +++ b/src/test/ui/dont-suggest-private-trait-method.stderr @@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `new` found for struct `T` in --> $DIR/dont-suggest-private-trait-method.rs:4:8 | LL | struct T; - | --------- function or associated item `new` not found for this + | -------- function or associated item `new` not found for this struct ... LL | T::new(); | ^^^ function or associated item not found in `T` diff --git a/src/test/ui/drop/repeat-drop-2.rs b/src/test/ui/drop/repeat-drop-2.rs index 2e7855328ecbf..59d5ef202051a 100644 --- a/src/test/ui/drop/repeat-drop-2.rs +++ b/src/test/ui/drop/repeat-drop-2.rs @@ -9,7 +9,7 @@ const _: [String; 0] = [String::new(); 0]; fn must_be_init() { let x: u8; - let _ = [x; 0]; //~ ERROR: use of possibly-uninitialized variable: `x` + let _ = [x; 0]; //~ ERROR E0381 } fn main() {} diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr index cdc58180c37b4..48fa2bfa975c0 100644 --- a/src/test/ui/drop/repeat-drop-2.stderr +++ b/src/test/ui/drop/repeat-drop-2.stderr @@ -17,11 +17,13 @@ LL | const _: [String; 0] = [String::new(); 0]; | |constants cannot evaluate destructors | value is dropped here -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/repeat-drop-2.rs:12:14 | +LL | let x: u8; + | - binding declared here but left uninitialized LL | let _ = [x; 0]; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error: aborting due to 3 previous errors diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs index 6ca5f5e3c5fcf..43c1c7759789d 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs @@ -23,5 +23,4 @@ enum FingerTree<T:'static> { fn main() { let ft = //~ ERROR overflow while adding drop-check rules for FingerTree FingerTree::Single(1); - //~^ ERROR overflow while adding drop-check rules for FingerTree } diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr index 5df69e4649df5..c447e2f7987cc 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr @@ -6,13 +6,5 @@ LL | let ft = | = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -error[E0320]: overflow while adding drop-check rules for FingerTree<i32> - --> $DIR/dropck_no_diverge_on_nonregular_1.rs:25:9 - | -LL | FingerTree::Single(1); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs index d34f7e326d15f..edd07652e53f7 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs @@ -22,5 +22,4 @@ enum FingerTree<T:'static> { fn main() { let ft = //~ ERROR overflow while adding drop-check rules for FingerTree FingerTree::Single(1); - //~^ ERROR overflow while adding drop-check rules for FingerTree } diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr index d34097d401004..cd4706dd903f4 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr @@ -6,13 +6,5 @@ LL | let ft = | = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -error[E0320]: overflow while adding drop-check rules for FingerTree<i32> - --> $DIR/dropck_no_diverge_on_nonregular_2.rs:24:9 - | -LL | FingerTree::Single(1); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs index 558b4342da74d..af7402ca4a1ce 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs @@ -31,6 +31,5 @@ enum Wrapper<T:'static> { fn main() { let w = //~ ERROR overflow while adding drop-check rules for Option Some(Wrapper::Simple::<u32>); - //~^ ERROR overflow while adding drop-check rules for Option - //~| ERROR overflow while adding drop-check rules for Wrapper + //~^ ERROR overflow while adding drop-check rules for Wrapper } diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index b24e1d1bf7927..18cd1b6cd413b 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -6,14 +6,6 @@ LL | let w = | = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -error[E0320]: overflow while adding drop-check rules for Option<Wrapper<u32>> - --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9 - | -LL | Some(Wrapper::Simple::<u32>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - error[E0320]: overflow while adding drop-check rules for Wrapper<u32> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:14 | @@ -22,5 +14,5 @@ LL | Some(Wrapper::Simple::<u32>); | = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/dropck/issue-38868.stderr b/src/test/ui/dropck/issue-38868.stderr index f267abc0bfa79..ec81c2ea646f8 100644 --- a/src/test/ui/dropck/issue-38868.stderr +++ b/src/test/ui/dropck/issue-38868.stderr @@ -1,21 +1,15 @@ error[E0366]: `Drop` impls cannot be specialized --> $DIR/issue-38868.rs:5:1 | -LL | / impl Drop for List<i32> { -LL | | fn drop(&mut self) { -LL | | panic!() -LL | | } -LL | | } - | |_^ +LL | impl Drop for List<i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: `i32` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/issue-38868.rs:1:1 | -LL | / pub struct List<T> { -LL | | head: T, -LL | | } - | |_^ +LL | pub struct List<T> { + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/dropck/reject-specialized-drops-8142.stderr b/src/test/ui/dropck/reject-specialized-drops-8142.stderr index 7f50cf5ab15d2..ebd484b880001 100644 --- a/src/test/ui/dropck/reject-specialized-drops-8142.stderr +++ b/src/test/ui/dropck/reject-specialized-drops-8142.stderr @@ -8,7 +8,7 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:4:1 | LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:28:67 @@ -20,33 +20,33 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:5:1 | LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:34:1 | LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `'static` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:7:1 | LL | struct N<'n> { x: &'n i8 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:39:1 | LL | impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `i8` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:9:1 | LL | struct P<Tp> { x: *const Tp } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:42:14 @@ -58,7 +58,7 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:10:1 | LL | struct Q<Tq> { x: *const Tq } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:45:21 @@ -70,59 +70,59 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:11:1 | LL | struct R<Tr> { x: *const Tr } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:54:1 | LL | impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `One` is mentioned multiple times note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:15:1 | LL | struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:57:1 | LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `'lw` is mentioned multiple times note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:16:1 | LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:60:1 | LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `3_usize` is not a generic parameter note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:17:1 | LL | struct X<const Ca: usize>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0366]: `Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:63:1 | LL | impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `Ca` is mentioned multiple times note: use the same sequence of generic lifetime, type and const parameters as the struct definition --> $DIR/reject-specialized-drops-8142.rs:18:1 | LL | struct Y<const Ca: usize, const Cb: usize>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:66:14 @@ -134,7 +134,7 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:20:1 | LL | enum Enum<T> { Variant(T) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:69:14 @@ -146,7 +146,7 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:21:1 | LL | struct TupleStruct<T>(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:72:21 @@ -158,7 +158,7 @@ note: the implementor must specify the same requirement --> $DIR/reject-specialized-drops-8142.rs:22:1 | LL | union Union<T: Copy> { f: T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 13 previous errors diff --git a/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr index 5176684e15340..3d9685db683f6 100644 --- a/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr +++ b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr @@ -7,10 +7,8 @@ LL | T: 'static, note: the implementor must specify the same requirement --> $DIR/relate_lt_in_type_outlives_bound.rs:1:1 | -LL | / struct Wrapper<'a, T>(&'a T) -LL | | where -LL | | T: 'a; - | |__________^ +LL | struct Wrapper<'a, T>(&'a T) + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/dst/dst-bad-coerce1.stderr b/src/test/ui/dst/dst-bad-coerce1.stderr index 121c76a01a5de..594acff853a0e 100644 --- a/src/test/ui/dst/dst-bad-coerce1.stderr +++ b/src/test/ui/dst/dst-bad-coerce1.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied LL | let f3: &Fat<dyn Bar> = f2; | ^^ the trait `Bar` is not implemented for `Foo` | - = note: required for the cast to the object type `dyn Bar` + = note: required for the cast from `Foo` to the object type `dyn Bar` error[E0308]: mismatched types --> $DIR/dst-bad-coerce1.rs:28:27 @@ -34,7 +34,7 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied LL | let f3: &(dyn Bar,) = f2; | ^^ the trait `Bar` is not implemented for `Foo` | - = note: required for the cast to the object type `dyn Bar` + = note: required for the cast from `Foo` to the object type `dyn Bar` error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-index.stderr b/src/test/ui/dst/dst-index.stderr index 6bcd70cbaad45..d38af3f89c21b 100644 --- a/src/test/ui/dst/dst-index.stderr +++ b/src/test/ui/dst/dst-index.stderr @@ -1,14 +1,14 @@ -error[E0161]: cannot move a value of type str: the size of str cannot be statically determined +error[E0161]: cannot move a value of type `str` --> $DIR/dst-index.rs:31:5 | LL | S[0]; - | ^^^^ + | ^^^^ the size of `str` cannot be statically determined -error[E0161]: cannot move a value of type dyn Debug: the size of dyn Debug cannot be statically determined +error[E0161]: cannot move a value of type `dyn Debug` --> $DIR/dst-index.rs:34:5 | LL | T[0]; - | ^^^^ + | ^^^^ the size of `dyn Debug` cannot be statically determined error[E0507]: cannot move out of index of `S` --> $DIR/dst-index.rs:31:5 diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index 5bd47736626da..e24c96ebed633 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -6,7 +6,7 @@ LL | fn test1<T: ?Sized + Foo>(t: &T) { LL | let u: &dyn Foo = t; | ^ doesn't have a size known at compile-time | - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast from `T` to the object type `dyn Foo` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn test1<T: ?Sized + Foo>(t: &T) { @@ -21,7 +21,7 @@ LL | fn test2<T: ?Sized + Foo>(t: &T) { LL | let v: &dyn Foo = t as &dyn Foo; | ^ doesn't have a size known at compile-time | - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast from `T` to the object type `dyn Foo` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn test2<T: ?Sized + Foo>(t: &T) { @@ -35,7 +35,7 @@ LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast from `str` to the object type `dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/dst-object-from-unsized-type.rs:23:23 @@ -44,7 +44,7 @@ LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast from `[u8]` to the object type `dyn Foo` error: aborting due to 4 previous errors diff --git a/src/test/ui/duplicate/dupe-symbols-6.stderr b/src/test/ui/duplicate/dupe-symbols-6.stderr index 8d5b7fb35bf0b..6692a63dce8f9 100644 --- a/src/test/ui/duplicate/dupe-symbols-6.stderr +++ b/src/test/ui/duplicate/dupe-symbols-6.stderr @@ -2,7 +2,7 @@ error: symbol `fail` is already defined --> $DIR/dupe-symbols-6.rs:10:1 | LL | static HELLO_TWICE: u16 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr index 48e5ea8ec866c..5fc0a916a09c1 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.stderr +++ b/src/test/ui/empty/empty-struct-braces-expr.stderr @@ -10,7 +10,7 @@ LL | let e1 = Empty1; ::: $DIR/auxiliary/empty-struct.rs:2:1 | LL | pub struct XEmpty2; - | ------------------- similarly named unit struct `XEmpty2` defined here + | ------------------ similarly named unit struct `XEmpty2` defined here | help: use struct literal syntax instead | @@ -33,7 +33,7 @@ LL | let e1 = Empty1(); ::: $DIR/auxiliary/empty-struct.rs:2:1 | LL | pub struct XEmpty2; - | ------------------- similarly named unit struct `XEmpty2` defined here + | ------------------ similarly named unit struct `XEmpty2` defined here | help: use struct literal syntax instead | @@ -73,7 +73,7 @@ LL | let xe1 = XEmpty1; LL | pub struct XEmpty1 {} | ------------------ `XEmpty1` defined here LL | pub struct XEmpty2; - | ------------------- similarly named unit struct `XEmpty2` defined here + | ------------------ similarly named unit struct `XEmpty2` defined here | help: use struct literal syntax instead | @@ -95,7 +95,7 @@ LL | let xe1 = XEmpty1(); LL | pub struct XEmpty1 {} | ------------------ `XEmpty1` defined here LL | pub struct XEmpty2; - | ------------------- similarly named unit struct `XEmpty2` defined here + | ------------------ similarly named unit struct `XEmpty2` defined here | help: use struct literal syntax instead | diff --git a/src/test/ui/empty/empty-struct-braces-pat-2.stderr b/src/test/ui/empty/empty-struct-braces-pat-2.stderr index 28191615afda4..7fb5cb2034a83 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-2.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-2.stderr @@ -10,7 +10,7 @@ LL | Empty1() => () ::: $DIR/auxiliary/empty-struct.rs:3:1 | LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use struct pattern syntax instead | @@ -33,7 +33,7 @@ LL | pub struct XEmpty1 {} | ------------------ `XEmpty1` defined here LL | pub struct XEmpty2; LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use struct pattern syntax instead | @@ -56,7 +56,7 @@ LL | Empty1(..) => () ::: $DIR/auxiliary/empty-struct.rs:3:1 | LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use struct pattern syntax instead | @@ -79,7 +79,7 @@ LL | pub struct XEmpty1 {} | ------------------ `XEmpty1` defined here LL | pub struct XEmpty2; LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use struct pattern syntax instead | diff --git a/src/test/ui/empty/empty-struct-braces-pat-3.stderr b/src/test/ui/empty/empty-struct-braces-pat-3.stderr index 60266bb35807d..615e7fb4aae29 100644 --- a/src/test/ui/empty/empty-struct-braces-pat-3.stderr +++ b/src/test/ui/empty/empty-struct-braces-pat-3.stderr @@ -19,7 +19,7 @@ LL | XEmpty3 {}, | ------- `XE::XEmpty3` defined here LL | XEmpty4, LL | XEmpty5(), - | --------- similarly named tuple variant `XEmpty5` defined here + | ------- similarly named tuple variant `XEmpty5` defined here | help: use struct pattern syntax instead | @@ -51,7 +51,7 @@ LL | XEmpty3 {}, | ------- `XE::XEmpty3` defined here LL | XEmpty4, LL | XEmpty5(), - | --------- similarly named tuple variant `XEmpty5` defined here + | ------- similarly named tuple variant `XEmpty5` defined here | help: use struct pattern syntax instead | diff --git a/src/test/ui/empty/empty-struct-tuple-pat.stderr b/src/test/ui/empty/empty-struct-tuple-pat.stderr index e696b85c6cc81..8d0f75d204c2f 100644 --- a/src/test/ui/empty/empty-struct-tuple-pat.stderr +++ b/src/test/ui/empty/empty-struct-tuple-pat.stderr @@ -5,7 +5,10 @@ LL | struct Empty2(); | ---------------- the tuple struct `Empty2` is defined here ... LL | Empty2 => () - | ^^^^^^ cannot be named the same as a tuple struct + | ^^^^^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `Empty2(..)` error[E0530]: match bindings cannot shadow tuple structs --> $DIR/empty-struct-tuple-pat.rs:25:9 @@ -14,7 +17,10 @@ LL | use empty_struct::*; | --------------- the tuple struct `XEmpty6` is imported here ... LL | XEmpty6 => () - | ^^^^^^^ cannot be named the same as a tuple struct + | ^^^^^^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `XEmpty6(..)` error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::Empty4` --> $DIR/empty-struct-tuple-pat.rs:29:9 @@ -36,7 +42,7 @@ LL | XE::XEmpty5 => (), LL | XEmpty4, | ------- similarly named unit variant `XEmpty4` defined here LL | XEmpty5(), - | --------- `XE::XEmpty5` defined here + | ------- `XE::XEmpty5` defined here | help: use the tuple variant pattern syntax instead | diff --git a/src/test/ui/empty/empty-struct-unit-expr.stderr b/src/test/ui/empty/empty-struct-unit-expr.stderr index c15253ba9cd78..cd51274dce81b 100644 --- a/src/test/ui/empty/empty-struct-unit-expr.stderr +++ b/src/test/ui/empty/empty-struct-unit-expr.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `Empty2` --> $DIR/empty-struct-unit-expr.rs:15:14 | LL | struct Empty2; - | -------------- `Empty2` defined here + | ------------- `Empty2` defined here ... LL | let e2 = Empty2(); | ^^^^^^-- diff --git a/src/test/ui/empty/empty-struct-unit-pat.stderr b/src/test/ui/empty/empty-struct-unit-pat.stderr index b1b253385fd34..5c0b4cffa9469 100644 --- a/src/test/ui/empty/empty-struct-unit-pat.stderr +++ b/src/test/ui/empty/empty-struct-unit-pat.stderr @@ -10,7 +10,7 @@ LL | Empty2() => () ::: $DIR/auxiliary/empty-struct.rs:3:1 | LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use this syntax instead | @@ -30,9 +30,9 @@ LL | XEmpty2() => () ::: $DIR/auxiliary/empty-struct.rs:2:1 | LL | pub struct XEmpty2; - | ------------------- `XEmpty2` defined here + | ------------------ `XEmpty2` defined here LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use this syntax instead | @@ -55,7 +55,7 @@ LL | Empty2(..) => () ::: $DIR/auxiliary/empty-struct.rs:3:1 | LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use this syntax instead | @@ -75,9 +75,9 @@ LL | XEmpty2(..) => () ::: $DIR/auxiliary/empty-struct.rs:2:1 | LL | pub struct XEmpty2; - | ------------------- `XEmpty2` defined here + | ------------------ `XEmpty2` defined here LL | pub struct XEmpty6(); - | --------------------- similarly named tuple struct `XEmpty6` defined here + | ------------------ similarly named tuple struct `XEmpty6` defined here | help: use this syntax instead | @@ -108,7 +108,7 @@ LL | XE::XEmpty4() => (), LL | XEmpty4, | ------- `XE::XEmpty4` defined here LL | XEmpty5(), - | --------- similarly named tuple variant `XEmpty5` defined here + | ------- similarly named tuple variant `XEmpty5` defined here | help: use this syntax instead | @@ -139,7 +139,7 @@ LL | XE::XEmpty4(..) => (), LL | XEmpty4, | ------- `XE::XEmpty4` defined here LL | XEmpty5(), - | --------- similarly named tuple variant `XEmpty5` defined here + | ------- similarly named tuple variant `XEmpty5` defined here | help: use this syntax instead | diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr index 2db5372da0c6e..803bb06fcc218 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr @@ -1,13 +1,8 @@ error[E0732]: `#[repr(inttype)]` must be specified --> $DIR/arbitrary_enum_discriminant-no-repr.rs:4:1 | -LL | / enum Enum { -LL | | -LL | | Unit = 1, -LL | | Tuple() = 2, -LL | | Struct{} = 3, -LL | | } - | |_^ +LL | enum Enum { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/enum/enum-discrim-autosizing.stderr b/src/test/ui/enum/enum-discrim-autosizing.stderr index bcd362b0632a2..eacea86d67e55 100644 --- a/src/test/ui/enum/enum-discrim-autosizing.stderr +++ b/src/test/ui/enum/enum-discrim-autosizing.stderr @@ -1,16 +1,14 @@ error[E0081]: discriminant value `0` assigned more than once --> $DIR/enum-discrim-autosizing.rs:6:1 | -LL | / enum Eu64 { -LL | | -LL | | Au64 = 0, - | | - first assignment of `0` -LL | | -LL | | Bu64 = 0x8000_0000_0000_0000 - | | --------------------- second assignment of `0` (overflowed from `9223372036854775808`) -LL | | -LL | | } - | |_^ +LL | enum Eu64 { + | ^^^^^^^^^ +LL | +LL | Au64 = 0, + | - first assignment of `0` +LL | +LL | Bu64 = 0x8000_0000_0000_0000 + | --------------------- second assignment of `0` (overflowed from `9223372036854775808`) error: aborting due to previous error diff --git a/src/test/ui/enum/suggest-default-attribute.rs b/src/test/ui/enum/suggest-default-attribute.rs new file mode 100644 index 0000000000000..1d7567e60a57c --- /dev/null +++ b/src/test/ui/enum/suggest-default-attribute.rs @@ -0,0 +1,8 @@ +pub enum Test { //~ HELP consider adding a derive + #[default] + //~^ ERROR cannot find attribute `default` in this scope + First, + Second, +} + +fn main() {} diff --git a/src/test/ui/enum/suggest-default-attribute.stderr b/src/test/ui/enum/suggest-default-attribute.stderr new file mode 100644 index 0000000000000..fb830d3f78b64 --- /dev/null +++ b/src/test/ui/enum/suggest-default-attribute.stderr @@ -0,0 +1,14 @@ +error: cannot find attribute `default` in this scope + --> $DIR/suggest-default-attribute.rs:2:7 + | +LL | #[default] + | ^^^^^^^ + | +help: consider adding a derive + | +LL + #[derive(Default)] +LL ~ pub enum Test { + | + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr index d4519af540859..6f5bb4309c350 100644 --- a/src/test/ui/error-codes/E0004-2.stderr +++ b/src/test/ui/error-codes/E0004-2.stderr @@ -7,17 +7,14 @@ LL | match x { } note: `Option<i32>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | None, - | | ^^^^ not covered -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), - | | ^^^^ not covered -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | None, + | ^^^^ not covered +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered = note: the matched value is of type `Option<i32>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr index 55b1112b5f8ec..f01a77bd374b6 100644 --- a/src/test/ui/error-codes/E0005.stderr +++ b/src/test/ui/error-codes/E0005.stderr @@ -9,16 +9,11 @@ LL | let Some(y) = x; note: `Option<i32>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | None, - | | ^^^^ not covered -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | None, + | ^^^^ not covered = note: the matched value is of type `Option<i32>` help: you might want to use `if let` to ignore the variant that isn't matched | diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 7d959b6d148ed..830e4db345ac0 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -11,7 +11,7 @@ note: `const` item defined here --> $DIR/E0017.rs:2:1 | LL | const C: i32 = 2; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants --> $DIR/E0017.rs:5:30 @@ -52,7 +52,7 @@ note: `const` item defined here --> $DIR/E0017.rs:2:1 | LL | const C: i32 = 2; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics --> $DIR/E0017.rs:11:38 diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr index 3697b5fcf154d..2307f52c93bce 100644 --- a/src/test/ui/error-codes/E0057.stderr +++ b/src/test/ui/error-codes/E0057.stderr @@ -18,7 +18,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 | LL | let c = f(2, 3); - | ^ - argument unexpected + | ^ - argument of type `{integer}` unexpected | note: closure defined here --> $DIR/E0057.rs:2:13 diff --git a/src/test/ui/error-codes/E0075.stderr b/src/test/ui/error-codes/E0075.stderr index d8b90d0691dad..3f927726a030f 100644 --- a/src/test/ui/error-codes/E0075.stderr +++ b/src/test/ui/error-codes/E0075.stderr @@ -2,7 +2,7 @@ error[E0075]: SIMD vector cannot be empty --> $DIR/E0075.rs:4:1 | LL | struct Bad; - | ^^^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0076.stderr b/src/test/ui/error-codes/E0076.stderr index 2c2842d152b5e..7d4ff87981686 100644 --- a/src/test/ui/error-codes/E0076.stderr +++ b/src/test/ui/error-codes/E0076.stderr @@ -2,7 +2,7 @@ error[E0076]: SIMD vector should be homogeneous --> $DIR/E0076.rs:4:1 | LL | struct Bad(u16, u32, u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type + | ^^^^^^^^^^ SIMD elements must have the same type error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0077.stderr b/src/test/ui/error-codes/E0077.stderr index 1938a9a272a16..9a84b2ec4069f 100644 --- a/src/test/ui/error-codes/E0077.stderr +++ b/src/test/ui/error-codes/E0077.stderr @@ -2,7 +2,7 @@ error[E0077]: SIMD vector element type should be a primitive scalar (integer/flo --> $DIR/E0077.rs:4:1 | LL | struct Bad(String); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr index d7c7dbac7d647..ff6113646bb8a 100644 --- a/src/test/ui/error-codes/E0081.stderr +++ b/src/test/ui/error-codes/E0081.stderr @@ -1,48 +1,41 @@ error[E0081]: discriminant value `3` assigned more than once --> $DIR/E0081.rs:1:1 | -LL | / enum Enum { -LL | | -LL | | P = 3, - | | - first assignment of `3` -LL | | -LL | | X = 3, - | | - second assignment of `3` -LL | | -LL | | Y = 5 -LL | | } - | |_^ +LL | enum Enum { + | ^^^^^^^^^ +LL | +LL | P = 3, + | - first assignment of `3` +LL | +LL | X = 3, + | - second assignment of `3` error[E0081]: discriminant value `1` assigned more than once --> $DIR/E0081.rs:11:1 | -LL | / enum EnumOverflowRepr { -LL | | -LL | | P = 257, - | | --- first assignment of `1` (overflowed from `257`) -LL | | -LL | | X = 513, - | | --- second assignment of `1` (overflowed from `513`) -LL | | -LL | | } - | |_^ +LL | enum EnumOverflowRepr { + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | P = 257, + | --- first assignment of `1` (overflowed from `257`) +LL | +LL | X = 513, + | --- second assignment of `1` (overflowed from `513`) error[E0081]: discriminant value `-1` assigned more than once --> $DIR/E0081.rs:20:1 | -LL | / enum NegDisEnum { -LL | | -LL | | First = -1, - | | -- first assignment of `-1` -LL | | -LL | | Second = -2, - | | ----------- assigned discriminant for `Last` was incremented from this discriminant -LL | | -LL | | Last, - | | ---- second assignment of `-1` -LL | | -LL | | } - | |_^ +LL | enum NegDisEnum { + | ^^^^^^^^^^^^^^^ +LL | +LL | First = -1, + | -- first assignment of `-1` +LL | +LL | Second = -2, + | ----------- assigned discriminant for `Last` was incremented from this discriminant +LL | +LL | Last, + | ---- second assignment of `-1` error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0084.stderr b/src/test/ui/error-codes/E0084.stderr index 1f818da25bb0f..e1bda22b8d19a 100644 --- a/src/test/ui/error-codes/E0084.stderr +++ b/src/test/ui/error-codes/E0084.stderr @@ -4,7 +4,7 @@ error[E0084]: unsupported representation for zero-variant enum LL | #[repr(i32)] | ^^^^^^^^^^^^ LL | enum Foo {} - | ----------- zero-variant enum + | -------- zero-variant enum error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index 5cdfe1cc5562d..29f7e4ad683d3 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -2,7 +2,7 @@ error[E0152]: found duplicate lang item `owned_box` --> $DIR/E0152.rs:5:1 | LL | struct Foo<T>(T); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: the lang item is first defined in crate `alloc` (which `std` depends on) = note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib diff --git a/src/test/ui/error-codes/E0161.base.stderr b/src/test/ui/error-codes/E0161.base.stderr index fb578cda17e9f..15d98b657a262 100644 --- a/src/test/ui/error-codes/E0161.base.stderr +++ b/src/test/ui/error-codes/E0161.base.stderr @@ -1,8 +1,8 @@ -error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined +error[E0161]: cannot move a value of type `dyn Bar` --> $DIR/E0161.rs:16:5 | LL | x.f(); - | ^^^^^ + | ^^^^^ the size of `dyn Bar` cannot be statically determined error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0191.stderr b/src/test/ui/error-codes/E0191.stderr index d69a14916e198..cf80c9c46ca2c 100644 --- a/src/test/ui/error-codes/E0191.stderr +++ b/src/test/ui/error-codes/E0191.stderr @@ -2,7 +2,7 @@ error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must b --> $DIR/E0191.rs:5:16 | LL | type Bar; - | --------- `Bar` defined here + | -------- `Bar` defined here ... LL | type Foo = dyn Trait; | ^^^^^ help: specify the associated type: `Trait<Bar = Type>` diff --git a/src/test/ui/error-codes/E0201.stderr b/src/test/ui/error-codes/E0201.stderr index 89cfd4024230b..94e06894144ca 100644 --- a/src/test/ui/error-codes/E0201.stderr +++ b/src/test/ui/error-codes/E0201.stderr @@ -2,26 +2,26 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/E0201.rs:5:5 | LL | fn bar(&self) -> bool { self.0 > 5 } - | ------------------------------------ previous definition of `bar` here + | --------------------- previous definition of `bar` here LL | fn bar() {} - | ^^^^^^^^^^^ duplicate definition + | ^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `baz`: --> $DIR/E0201.rs:17:5 | LL | fn baz(&self) -> bool { true } - | ------------------------------ previous definition of `baz` here + | --------------------- previous definition of `baz` here LL | fn baz(&self) -> bool { self.0 > 5 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `Quux`: --> $DIR/E0201.rs:18:5 | LL | type Quux = u32; - | ---------------- previous definition of `Quux` here + | --------- previous definition of `Quux` here ... LL | type Quux = u32; - | ^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^ duplicate definition error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0220.stderr b/src/test/ui/error-codes/E0220.stderr index 4fa83d8bf6e82..11763ce788dac 100644 --- a/src/test/ui/error-codes/E0220.stderr +++ b/src/test/ui/error-codes/E0220.stderr @@ -8,7 +8,7 @@ error[E0191]: the value of the associated type `Bar` (from trait `Trait`) must b --> $DIR/E0220.rs:5:16 | LL | type Bar; - | --------- `Bar` defined here + | -------- `Bar` defined here ... LL | type Foo = dyn Trait<F=i32>; | ^^^^^^^^^^^^ help: specify the associated type: `Trait<F=i32, Bar = Type>` diff --git a/src/test/ui/error-codes/E0221.stderr b/src/test/ui/error-codes/E0221.stderr index f3dbf122de3ba..5414d77ad7c51 100644 --- a/src/test/ui/error-codes/E0221.stderr +++ b/src/test/ui/error-codes/E0221.stderr @@ -2,10 +2,10 @@ error[E0221]: ambiguous associated type `A` in bounds of `Self` --> $DIR/E0221.rs:11:16 | LL | type A: T1; - | ----------- ambiguous `A` from `Foo` + | ---------- ambiguous `A` from `Foo` ... LL | type A: T2; - | ----------- ambiguous `A` from `Bar` + | ---------- ambiguous `A` from `Bar` LL | fn do_something() { LL | let _: Self::A; | ^^^^^^^ ambiguous associated type `A` @@ -23,7 +23,7 @@ error[E0221]: ambiguous associated type `Err` in bounds of `Self` --> $DIR/E0221.rs:21:16 | LL | type Err: T3; - | ------------- ambiguous `Err` from `My` + | ------------ ambiguous `Err` from `My` LL | fn test() { LL | let _: Self::Err; | ^^^^^^^^^ ambiguous associated type `Err` diff --git a/src/test/ui/error-codes/E0264.stderr b/src/test/ui/error-codes/E0264.stderr index 403c0aa4146c7..e8e35a12cbb49 100644 --- a/src/test/ui/error-codes/E0264.stderr +++ b/src/test/ui/error-codes/E0264.stderr @@ -2,7 +2,7 @@ error[E0264]: unknown external lang item: `cake` --> $DIR/E0264.rs:5:5 | LL | fn cake(); - | ^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0297.stderr b/src/test/ui/error-codes/E0297.stderr index 95d95003c616f..693b079238d71 100644 --- a/src/test/ui/error-codes/E0297.stderr +++ b/src/test/ui/error-codes/E0297.stderr @@ -7,16 +7,11 @@ LL | for Some(x) in xs {} note: `Option<i32>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | None, - | | ^^^^ not covered -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | None, + | ^^^^ not covered = note: the matched value is of type `Option<i32>` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0374.stderr b/src/test/ui/error-codes/E0374.stderr index 7ab0f82fc2360..68e15e6f8fe81 100644 --- a/src/test/ui/error-codes/E0374.stderr +++ b/src/test/ui/error-codes/E0374.stderr @@ -1,9 +1,8 @@ error[E0374]: the trait `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced, none found --> $DIR/E0374.rs:8:1 | -LL | / impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> -LL | | where T: CoerceUnsized<U> {} - | |________________________________^ +LL | impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0376.stderr b/src/test/ui/error-codes/E0376.stderr index 015448c39eaaa..e91efb045c156 100644 --- a/src/test/ui/error-codes/E0376.stderr +++ b/src/test/ui/error-codes/E0376.stderr @@ -2,7 +2,7 @@ error[E0376]: the trait `CoerceUnsized` may only be implemented for a coercion b --> $DIR/E0376.rs:8:1 | LL | impl<T, U> CoerceUnsized<U> for Foo<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index 4886a156d2ea5..106efc19ac9cf 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -11,7 +11,7 @@ note: `const` item defined here --> $DIR/E0388.rs:2:1 | LL | const C: i32 = 2; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of constants --> $DIR/E0388.rs:4:30 @@ -52,7 +52,7 @@ note: `const` item defined here --> $DIR/E0388.rs:2:1 | LL | const C: i32 = 2; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics --> $DIR/E0388.rs:10:38 diff --git a/src/test/ui/error-codes/E0393.stderr b/src/test/ui/error-codes/E0393.stderr index 8aadf5c8b4712..d9f70b7293016 100644 --- a/src/test/ui/error-codes/E0393.stderr +++ b/src/test/ui/error-codes/E0393.stderr @@ -2,7 +2,7 @@ error[E0393]: the type parameter `T` must be explicitly specified --> $DIR/E0393.rs:3:47 | LL | trait A<T=Self> {} - | ------------------ type parameter `T` must be specified for this + | --------------- type parameter `T` must be specified for this LL | LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} | ^ help: set the type parameter to the desired type: `A<T>` diff --git a/src/test/ui/error-codes/E0396-fixed.stderr b/src/test/ui/error-codes/E0396-fixed.stderr index 3eb291f0f7014..2efbd6989ad61 100644 --- a/src/test/ui/error-codes/E0396-fixed.stderr +++ b/src/test/ui/error-codes/E0396-fixed.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0396-fixed.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df is not a valid pointer + | ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df[noalloc] is a dangling pointer (it has no provenance) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0445.stderr b/src/test/ui/error-codes/E0445.stderr index 1a66e0a2f9758..23b7a33504767 100644 --- a/src/test/ui/error-codes/E0445.stderr +++ b/src/test/ui/error-codes/E0445.stderr @@ -5,7 +5,7 @@ LL | trait Foo { | --------- `Foo` declared as private ... LL | pub trait Bar : Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `Foo` in public interface --> $DIR/E0445.rs:7:1 @@ -14,7 +14,7 @@ LL | trait Foo { | --------- `Foo` declared as private ... LL | pub struct Bar2<T: Foo>(pub T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `Foo` in public interface --> $DIR/E0445.rs:9:1 diff --git a/src/test/ui/error-codes/E0446.stderr b/src/test/ui/error-codes/E0446.stderr index 35e79e448d5ac..b6a195c40a93a 100644 --- a/src/test/ui/error-codes/E0446.stderr +++ b/src/test/ui/error-codes/E0446.stderr @@ -2,7 +2,7 @@ error[E0446]: private type `Bar` in public interface --> $DIR/E0446.rs:4:5 | LL | struct Bar(u32); - | ---------------- `Bar` declared as private + | ---------- `Bar` declared as private LL | LL | pub fn bar() -> Bar { | ^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/error-codes/E0520.stderr b/src/test/ui/error-codes/E0520.stderr index be7b95465a5f7..65ebfcdbe32ca 100644 --- a/src/test/ui/error-codes/E0520.stderr +++ b/src/test/ui/error-codes/E0520.stderr @@ -11,13 +11,11 @@ LL | #![feature(specialization)] error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/E0520.rs:17:5 | -LL | / impl<T: Clone> SpaceLlama for T { -LL | | fn fly(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T: Clone> SpaceLlama for T { + | ------------------------------- parent `impl` is here ... -LL | default fn fly(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `fly` +LL | default fn fly(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `fly` | = note: to specialize, `fly` in the parent `impl` must be marked `default` diff --git a/src/test/ui/error-codes/E0599.stderr b/src/test/ui/error-codes/E0599.stderr index a78a003661d6f..a1fb58f483f6d 100644 --- a/src/test/ui/error-codes/E0599.stderr +++ b/src/test/ui/error-codes/E0599.stderr @@ -2,7 +2,7 @@ error[E0599]: no associated item named `NotEvenReal` found for struct `Foo` in t --> $DIR/E0599.rs:4:20 | LL | struct Foo; - | ----------- associated item `NotEvenReal` not found for this + | ---------- associated item `NotEvenReal` not found for this struct ... LL | || if let Foo::NotEvenReal() = Foo {}; | ^^^^^^^^^^^ associated item not found in `Foo` diff --git a/src/test/ui/error-codes/E0658.stderr b/src/test/ui/error-codes/E0658.stderr index 4563b0e21940b..8d423484528a1 100644 --- a/src/test/ui/error-codes/E0658.stderr +++ b/src/test/ui/error-codes/E0658.stderr @@ -1,10 +1,8 @@ error[E0658]: repr with 128-bit type is unstable --> $DIR/E0658.rs:2:1 | -LL | / enum Foo { -LL | | Bar(u64), -LL | | } - | |_^ +LL | enum Foo { + | ^^^^^^^^ | = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information = help: add `#![feature(repr128)]` to the crate attributes to enable diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 81aa268cacc5c..43122c13efba8 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -44,14 +44,8 @@ LL | enum Question { note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait Not { -LL | | /// The resulting type after applying the `!` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn not(self) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Not { + | ^^^^^^^^^^^^^ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:25:5 diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.rs b/src/test/ui/expr/if/attrs/let-chains-attr.rs index 2cd8731141af7..d62c2cb403fe8 100644 --- a/src/test/ui/expr/if/attrs/let-chains-attr.rs +++ b/src/test/ui/expr/if/attrs/let-chains-attr.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(let_chains)] - #[cfg(FALSE)] fn foo() { #[attr] diff --git a/src/test/ui/expr/if/bad-if-let-suggestion.rs b/src/test/ui/expr/if/bad-if-let-suggestion.rs index a8b2a283039fd..070a5b201286d 100644 --- a/src/test/ui/expr/if/bad-if-let-suggestion.rs +++ b/src/test/ui/expr/if/bad-if-let-suggestion.rs @@ -4,7 +4,6 @@ fn a() { if let x = 1 && i = 2 {} //~^ ERROR cannot find value `i` in this scope - //~| ERROR `let` expressions in this position are unstable //~| ERROR mismatched types //~| ERROR `let` expressions are not supported here } diff --git a/src/test/ui/expr/if/bad-if-let-suggestion.stderr b/src/test/ui/expr/if/bad-if-let-suggestion.stderr index 60d286fedf58a..9f7a21c7d1ad9 100644 --- a/src/test/ui/expr/if/bad-if-let-suggestion.stderr +++ b/src/test/ui/expr/if/bad-if-let-suggestion.stderr @@ -13,7 +13,7 @@ LL | if let x = 1 && i = 2 {} | ^ not found in this scope error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:13:9 + --> $DIR/bad-if-let-suggestion.rs:12:9 | LL | fn a() { | ------ similarly named function `a` defined here @@ -22,7 +22,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `j` in this scope - --> $DIR/bad-if-let-suggestion.rs:13:13 + --> $DIR/bad-if-let-suggestion.rs:12:13 | LL | fn a() { | ------ similarly named function `a` defined here @@ -31,7 +31,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:13:18 + --> $DIR/bad-if-let-suggestion.rs:12:18 | LL | fn a() { | ------ similarly named function `a` defined here @@ -40,7 +40,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `x` in this scope - --> $DIR/bad-if-let-suggestion.rs:20:8 + --> $DIR/bad-if-let-suggestion.rs:19:8 | LL | fn a() { | ------ similarly named function `a` defined here @@ -48,22 +48,13 @@ LL | fn a() { LL | if x[0] = 1 {} | ^ help: a function with a similar name exists: `a` -error[E0658]: `let` expressions in this position are unstable - --> $DIR/bad-if-let-suggestion.rs:5:8 - | -LL | if let x = 1 && i = 2 {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - error[E0308]: mismatched types --> $DIR/bad-if-let-suggestion.rs:5:8 | LL | if let x = 1 && i = 2 {} | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0308, E0425, E0658. +Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/extern/auxiliary/issue-80074-macro.rs b/src/test/ui/extern/auxiliary/issue-80074-macro.rs new file mode 100644 index 0000000000000..30e0f19ab8d84 --- /dev/null +++ b/src/test/ui/extern/auxiliary/issue-80074-macro.rs @@ -0,0 +1,4 @@ +// edition:2018 + +macro_rules! foo_ { () => {}; } +use foo_ as foo; diff --git a/src/test/ui/extern/extern-main-issue-86110.stderr b/src/test/ui/extern/extern-main-issue-86110.stderr index cd3de227dcffe..18dfddc46bd36 100644 --- a/src/test/ui/extern/extern-main-issue-86110.stderr +++ b/src/test/ui/extern/extern-main-issue-86110.stderr @@ -2,7 +2,7 @@ error: the `main` function cannot be declared in an `extern` block --> $DIR/extern-main-issue-86110.rs:4:5 | LL | fn main(); - | ^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extern/extern-static-size-overflow.stderr b/src/test/ui/extern/extern-static-size-overflow.stderr index f5173feec75d4..1c926399591c2 100644 --- a/src/test/ui/extern/extern-static-size-overflow.stderr +++ b/src/test/ui/extern/extern-static-size-overflow.stderr @@ -2,19 +2,19 @@ error: extern static is too large for the current architecture --> $DIR/extern-static-size-overflow.rs:38:5 | LL | static BAZ: [u8; max_size()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: extern static is too large for the current architecture --> $DIR/extern-static-size-overflow.rs:39:5 | LL | static UWU: [usize; usize::MAX]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: extern static is too large for the current architecture --> $DIR/extern-static-size-overflow.rs:40:5 | LL | static A: ReallyBig; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/extern/extern-types-distinct-types.stderr b/src/test/ui/extern/extern-types-distinct-types.stderr index f69629232aed1..ca25aa64eb8be 100644 --- a/src/test/ui/extern/extern-types-distinct-types.stderr +++ b/src/test/ui/extern/extern-types-distinct-types.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/extern-types-distinct-types.rs:9:5 | LL | type A; - | ------- the found foreign type + | ------ the found foreign type LL | type B; - | ------- the expected foreign type + | ------ the expected foreign type ... LL | fn foo(r: &A) -> &B { | -- expected `&B` because of return type diff --git a/src/test/ui/extern/issue-80074.rs b/src/test/ui/extern/issue-80074.rs new file mode 100644 index 0000000000000..f83027d4abfd2 --- /dev/null +++ b/src/test/ui/extern/issue-80074.rs @@ -0,0 +1,10 @@ +// edition:2018 +// build-pass +// aux-crate:issue_80074=issue-80074-macro.rs + +#[macro_use] +extern crate issue_80074; + +fn main() { + foo!(); +} diff --git a/src/test/ui/extern/issue-95829.rs b/src/test/ui/extern/issue-95829.rs new file mode 100644 index 0000000000000..3379148ae7bb0 --- /dev/null +++ b/src/test/ui/extern/issue-95829.rs @@ -0,0 +1,10 @@ +// edition:2018 + +extern { + async fn L() { //~ ERROR: incorrect function inside `extern` block + //~^ ERROR: functions in `extern` blocks cannot have qualifiers + async fn M() {} + } +} + +fn main() {} diff --git a/src/test/ui/extern/issue-95829.stderr b/src/test/ui/extern/issue-95829.stderr new file mode 100644 index 0000000000000..b902f0ef8f5c0 --- /dev/null +++ b/src/test/ui/extern/issue-95829.stderr @@ -0,0 +1,32 @@ +error: incorrect function inside `extern` block + --> $DIR/issue-95829.rs:4:14 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | async fn L() { + | ______________^___- + | | | + | | cannot have a body +LL | | +LL | | async fn M() {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/issue-95829.rs:4:14 + | +LL | extern { + | ------ in this `extern` block +LL | async fn L() { + | ^ + | +help: remove the qualifiers + | +LL | fn L() { + | ~~ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/extern/not-in-block.rs b/src/test/ui/extern/not-in-block.rs new file mode 100644 index 0000000000000..d3bcafdef7b3c --- /dev/null +++ b/src/test/ui/extern/not-in-block.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] + +extern fn none_fn(x: bool) -> i32; +//~^ ERROR free function without a body +extern "C" fn c_fn(x: bool) -> i32; +//~^ ERROR free function without a body diff --git a/src/test/ui/extern/not-in-block.stderr b/src/test/ui/extern/not-in-block.stderr new file mode 100644 index 0000000000000..2544949ab17a8 --- /dev/null +++ b/src/test/ui/extern/not-in-block.stderr @@ -0,0 +1,32 @@ +error: free function without a body + --> $DIR/not-in-block.rs:3:1 + | +LL | extern fn none_fn(x: bool) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: provide a definition for the function + | +LL | extern fn none_fn(x: bool) -> i32 { <body> } + | ~~~~~~~~~~ +help: if you meant to declare an externally defined function, use an `extern` block + | +LL | extern { fn none_fn(x: bool) -> i32; } + | ~~~~~~~~ + + +error: free function without a body + --> $DIR/not-in-block.rs:5:1 + | +LL | extern "C" fn c_fn(x: bool) -> i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: provide a definition for the function + | +LL | extern "C" fn c_fn(x: bool) -> i32 { <body> } + | ~~~~~~~~~~ +help: if you meant to declare an externally defined function, use an `extern` block + | +LL | extern "C" { fn c_fn(x: bool) -> i32; } + | ~~~~~~~~~~~~ + + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index a06c4b2b48310..a1c69a5afb611 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -1,13 +1,3 @@ -error[E0658]: `Ptr<Self>` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/feature-gate-arbitrary-self-types.rs:16:18 - | -LL | fn foo(self: Ptr<Self>); - | ^^^^^^^^^ - | - = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) - error[E0658]: `Ptr<Bar>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:22:18 | @@ -28,6 +18,16 @@ LL | fn bar(self: Box<Ptr<Self>>) {} = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) +error[E0658]: `Ptr<Self>` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/feature-gate-arbitrary-self-types.rs:16:18 + | +LL | fn foo(self: Ptr<Self>); + | ^^^^^^^^^ + | + = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index f9c53a66c4b84..a9f611b874527 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -8,20 +8,20 @@ LL | fn foo(self: *const Self) {} = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) -error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18 +error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 | -LL | fn bar(self: *const Self); +LL | fn bar(self: *const Self) {} | ^^^^^^^^^^^ | = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) -error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18 | -LL | fn bar(self: *const Self) {} +LL | fn bar(self: *const Self); | ^^^^^^^^^^^ | = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs index a93fb7977131d..4e020327447ff 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -1,7 +1,7 @@ // compile-flags: -Zsave-analysis // This is also a regression test for #69415 and the above flag is needed. -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; trait Tr1 { type As1: Copy; } trait Tr2 { type As2: Copy; } @@ -36,9 +36,9 @@ enum _En1<T: Tr1<As1: Tr2>> { union _Un1<T: Tr1<As1: Tr2>> { //~^ ERROR associated type bounds are unstable - outest: std::mem::ManuallyDrop<T>, - outer: T::As1, - inner: <T::As1 as Tr2>::As2, + outest: ManuallyDrop<T>, + outer: ManuallyDrop<T::As1>, + inner: ManuallyDrop<<T::As1 as Tr2>::As2>, } type _TaWhere1<T> where T: Iterator<Item: Copy> = T; diff --git a/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs new file mode 100644 index 0000000000000..b0b494fa3ff13 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs @@ -0,0 +1,8 @@ +fn main() { + for<> || -> () {}; + //~^ ERROR `for<...>` binders for closures are experimental + for<'a> || -> () {}; + //~^ ERROR `for<...>` binders for closures are experimental + for<'a, 'b> |_: &'a ()| -> () {}; + //~^ ERROR `for<...>` binders for closures are experimental +} diff --git a/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr new file mode 100644 index 0000000000000..aea5cfeed0705 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr @@ -0,0 +1,33 @@ +error[E0658]: `for<...>` binders for closures are experimental + --> $DIR/feature-gate-closure_lifetime_binder.rs:2:5 + | +LL | for<> || -> () {}; + | ^^^^^ + | + = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = help: consider removing `for<...>` + +error[E0658]: `for<...>` binders for closures are experimental + --> $DIR/feature-gate-closure_lifetime_binder.rs:4:5 + | +LL | for<'a> || -> () {}; + | ^^^^^^^ + | + = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = help: consider removing `for<...>` + +error[E0658]: `for<...>` binders for closures are experimental + --> $DIR/feature-gate-closure_lifetime_binder.rs:6:5 + | +LL | for<'a, 'b> |_: &'a ()| -> () {}; + | ^^^^^^^^^^^ + | + = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = help: consider removing `for<...>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index 21180f31bbd26..f8349391a0fe7 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -9,15 +9,11 @@ LL | let Ok(_x) = foo(); note: `Result<u32, !>` defined here --> $SRC_DIR/core/src/result.rs:LL:COL | -LL | / pub enum Result<T, E> { -LL | | /// Contains the success value -LL | | #[lang = "Ok"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E), - | | ^^^ not covered -LL | | } - | |_- +LL | pub enum Result<T, E> { + | --------------------- +... +LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E), + | ^^^ not covered = note: the matched value is of type `Result<u32, !>` help: you might want to use `if let` to ignore the variant that isn't matched | diff --git a/src/test/ui/feature-gates/feature-gate-repr128.stderr b/src/test/ui/feature-gates/feature-gate-repr128.stderr index 3eb005acc33b8..3999a6d2d2f89 100644 --- a/src/test/ui/feature-gates/feature-gate-repr128.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr128.stderr @@ -1,10 +1,8 @@ error[E0658]: repr with 128-bit type is unstable --> $DIR/feature-gate-repr128.rs:2:1 | -LL | / enum A { -LL | | A(u64) -LL | | } - | |_^ +LL | enum A { + | ^^^^^^ | = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information = help: add `#![feature(repr128)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs deleted file mode 100644 index af8d8e92b20bd..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ /dev/null @@ -1,35 +0,0 @@ -// ignore-tidy-linelength - -union U1 { // OK - a: u8, -} - -union U2<T: Copy> { // OK - a: T, -} - -union U22<T> { // OK - a: std::mem::ManuallyDrop<T>, -} - -union U3 { - a: String, //~ ERROR unions cannot contain fields that may need dropping -} - -union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! - a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable -} - -union U4<T> { - a: T, //~ ERROR unions cannot contain fields that may need dropping -} - -union U5 { // Having a drop impl is OK - a: u8, -} - -impl Drop for U5 { - fn drop(&mut self) {} -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr deleted file mode 100644 index 9e4a89f80c852..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable - --> $DIR/feature-gate-untagged_unions.rs:20:5 - | -LL | a: std::cell::RefCell<i32>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:16:5 - | -LL | a: String, - | ^^^^^^^^^ - | - = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type -help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped - | -LL | a: std::mem::ManuallyDrop<String>, - | +++++++++++++++++++++++ + - -error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:24:5 - | -LL | a: T, - | ^^^^ - | - = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type -help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped - | -LL | a: std::mem::ManuallyDrop<T>, - | +++++++++++++++++++++++ + - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0658, E0740. -For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 3f838fcf52355..5d6796b49448a 100644 --- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -259,7 +259,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] | ^^^^^^^^^ -warning: attribute should be applied to a function +warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:1 | LL | #[cold] @@ -272,7 +272,7 @@ LL | | mod inner { #![cold] } ... | LL | | LL | | } - | |_- not a function + | |_- not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -399,7 +399,7 @@ warning: `#[proc_macro_derive]` only has an effect on functions LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: attribute should be applied to a function +warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![cold] @@ -743,35 +743,35 @@ warning: crate-level attribute should be an inner attribute: add an exclamation LL | #[no_std] impl S { } | ^^^^^^^^^ -warning: attribute should be applied to a function +warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:17 | LL | mod inner { #![cold] } - | ------------^^^^^^^^-- not a function + | ------------^^^^^^^^-- not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to a function +warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 | LL | #[cold] struct S; - | ^^^^^^^ --------- not a function + | ^^^^^^^ --------- not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to a function +warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | LL | #[cold] type T = S; - | ^^^^^^^ ----------- not a function + | ^^^^^^^ ----------- not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to a function +warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 | LL | #[cold] impl S { } - | ^^^^^^^ ---------- not a function + | ^^^^^^^ ---------- not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/fn/fn-closure-mutable-capture.rs b/src/test/ui/fn/fn-closure-mutable-capture.rs index 0e427b9cf318f..97141886fe738 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.rs +++ b/src/test/ui/fn/fn-closure-mutable-capture.rs @@ -6,6 +6,7 @@ pub fn foo() { //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure //~| NOTE cannot assign //~| NOTE expects `Fn` instead of `FnMut` + //~| NOTE in this closure } fn main() {} diff --git a/src/test/ui/fn/fn-closure-mutable-capture.stderr b/src/test/ui/fn/fn-closure-mutable-capture.stderr index d23c363ae1582..03e3d545a9919 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.stderr +++ b/src/test/ui/fn/fn-closure-mutable-capture.stderr @@ -5,8 +5,9 @@ LL | pub fn bar<F: Fn()>(_f: F) {} | - change this to accept `FnMut` instead of `Fn` ... LL | bar(move || x = 1); - | --- ^^^^^ cannot assign - | | + | --- ------- ^^^^^ cannot assign + | | | + | | in this closure | expects `Fn` instead of `FnMut` error: aborting due to previous error diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr index 26eecf6a21d3d..95cf4fb168f1e 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr @@ -2,10 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5 | LL | fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds | - = help: consider adding an explicit lifetime bound `T: 'static`... - = note: ...so that the type `[T]` will meet its required lifetime bounds +help: consider adding an explicit lifetime bound... + | +LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/functions-closures/fn-help-with-err.stderr b/src/test/ui/functions-closures/fn-help-with-err.stderr index 3e42cb1fb6ec0..06e29daef456c 100644 --- a/src/test/ui/functions-closures/fn-help-with-err.stderr +++ b/src/test/ui/functions-closures/fn-help-with-err.stderr @@ -10,11 +10,11 @@ error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the curre LL | arc.blablabla(); | ^^^^^^^^^ method not found in `Arc<_>` -error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` in the current scope +error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>` in the current scope --> $DIR/fn-help-with-err.rs:12:10 | LL | arc2.blablabla(); - | ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` + | ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>` | | | this is a function, perhaps you wish to call it diff --git a/src/test/ui/future-incompatible-lint-group.stderr b/src/test/ui/future-incompatible-lint-group.stderr index d822847a7a589..8f6dde665e628 100644 --- a/src/test/ui/future-incompatible-lint-group.stderr +++ b/src/test/ui/future-incompatible-lint-group.stderr @@ -22,7 +22,7 @@ LL | #![deny(future_incompatible)] = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(future_incompatible)]` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730> - = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information + = note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generator/derived-drop-parent-expr.rs b/src/test/ui/generator/derived-drop-parent-expr.rs new file mode 100644 index 0000000000000..4bd34346a1815 --- /dev/null +++ b/src/test/ui/generator/derived-drop-parent-expr.rs @@ -0,0 +1,17 @@ +// build-pass +// compile-flags:-Zdrop-tracking + +//! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR +#![feature(generators)] + +fn assert_send<T: Send>(_thing: T) {} + +#[derive(Default)] +pub struct Client { pub nickname: String } + +fn main() { + let g = move || match drop(Client { ..Client::default() }) { + _status => yield, + }; + assert_send(g); +} diff --git a/src/test/ui/generator/drop-tracking-parent-expression.rs b/src/test/ui/generator/drop-tracking-parent-expression.rs new file mode 100644 index 0000000000000..d40f1b8f64d4a --- /dev/null +++ b/src/test/ui/generator/drop-tracking-parent-expression.rs @@ -0,0 +1,69 @@ +// compile-flags: -Zdrop-tracking +#![feature(generators, negative_impls, rustc_attrs)] + +macro_rules! type_combinations { + ( + $( $name:ident => { $( $tt:tt )* } );* $(;)? + ) => { $( + mod $name { + $( $tt )* + + impl !Sync for Client {} + impl !Send for Client {} + } + + // Struct update syntax. This fails because the Client used in the update is considered + // dropped *after* the yield. + { + let g = move || match drop($name::Client { ..$name::Client::default() }) { + //~^ `significant_drop::Client` which is not `Send` + //~| `insignificant_dtor::Client` which is not `Send` + //~| `derived_drop::Client` which is not `Send` + _ => yield, + }; + assert_send(g); + //~^ ERROR cannot be sent between threads + //~| ERROR cannot be sent between threads + //~| ERROR cannot be sent between threads + } + + // Simple owned value. This works because the Client is considered moved into `drop`, + // even though the temporary expression doesn't end until after the yield. + { + let g = move || match drop($name::Client::default()) { + _ => yield, + }; + assert_send(g); + } + )* } +} + +fn assert_send<T: Send>(_thing: T) {} + +fn main() { + type_combinations!( + // OK + copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; + // NOT OK: MIR borrowck thinks that this is used after the yield, even though + // this has no `Drop` impl and only the drops of the fields are observable. + // FIXME: this should compile. + derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; + // NOT OK + significant_drop => { + #[derive(Default)] + pub struct Client; + impl Drop for Client { + fn drop(&mut self) {} + } + }; + // NOT OK (we need to agree with MIR borrowck) + insignificant_dtor => { + #[derive(Default)] + #[rustc_insignificant_dtor] + pub struct Client; + impl Drop for Client { + fn drop(&mut self) {} + } + }; + ); +} diff --git a/src/test/ui/generator/drop-tracking-parent-expression.stderr b/src/test/ui/generator/drop-tracking-parent-expression.stderr new file mode 100644 index 0000000000000..522a300b3ed79 --- /dev/null +++ b/src/test/ui/generator/drop-tracking-parent-expression.stderr @@ -0,0 +1,128 @@ +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:24:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `derived_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:22:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `derived_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:41:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:24:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `significant_drop::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:22:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `significant_drop::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:41:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: generator cannot be sent between threads safely + --> $DIR/drop-tracking-parent-expression.rs:24:13 + | +LL | assert_send(g); + | ^^^^^^^^^^^ generator is not `Send` +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation + | + = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client` +note: generator is not `Send` as this value is used across a yield + --> $DIR/drop-tracking-parent-expression.rs:22:22 + | +LL | let g = move || match drop($name::Client { ..$name::Client::default() }) { + | ------------------------ has type `insignificant_dtor::Client` which is not `Send` +... +LL | _ => yield, + | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later +LL | }; + | - `$name::Client::default()` is later dropped here +... +LL | / type_combinations!( +LL | | // OK +LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; +LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though +... | +LL | | }; +LL | | ); + | |_____- in this macro invocation +note: required by a bound in `assert_send` + --> $DIR/drop-tracking-parent-expression.rs:41:19 + | +LL | fn assert_send<T: Send>(_thing: T) {} + | ^^^^ required by this bound in `assert_send` + = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/generator/drop-yield-twice.stderr b/src/test/ui/generator/drop-yield-twice.stderr index f821f2f40055f..5bc6ea5600fc5 100644 --- a/src/test/ui/generator/drop-yield-twice.stderr +++ b/src/test/ui/generator/drop-yield-twice.stderr @@ -4,7 +4,7 @@ error: generator cannot be sent between threads safely LL | assert_send(|| { | ^^^^^^^^^^^ generator is not `Send` | - = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 12:6]`, the trait `Send` is not implemented for `Foo` + = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 7:19]`, the trait `Send` is not implemented for `Foo` note: generator is not `Send` as this value is used across a yield --> $DIR/drop-yield-twice.rs:9:9 | diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr index 62a7b37a5a387..2a39a08ee39b2 100644 --- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 15:36] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 15:36]` --> $DIR/generator-yielding-or-returning-itself.rs:15:5 | LL | want_cyclic_generator_return(|| { @@ -16,7 +16,7 @@ LL | pub fn want_cyclic_generator_return<T>(_: T) LL | where T: Generator<Yield = (), Return = T> | ^^^^^^^^^^ required by this bound in `want_cyclic_generator_return` -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 28:35] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 28:35]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | LL | want_cyclic_generator_yield(|| { diff --git a/src/test/ui/generator/issue-57017.rs b/src/test/ui/generator/issue-57017.rs index 1223a3037abc7..c0bde3b4473e1 100644 --- a/src/test/ui/generator/issue-57017.rs +++ b/src/test/ui/generator/issue-57017.rs @@ -1,22 +1,55 @@ -// check-pass +// build-pass // compile-flags: -Zdrop-tracking #![feature(generators, negative_impls)] -struct Client; +macro_rules! type_combinations { + ( + $( $name:ident => { $( $tt:tt )* } );* + ) => { $( + mod $name { + pub mod unsync { + $( $tt )* -impl !Sync for Client {} + impl !Sync for Client {} + } + pub mod unsend { + $( $tt )* -fn status(_client_status: &Client) -> i16 { - 200 + impl !Send for Client {} + } + } + + // This is the same bug as issue 57017, but using yield instead of await + { + let g = move || match drop(&$name::unsync::Client::default()) { + _status => yield, + }; + assert_send(g); + } + + // This tests that `Client` is properly considered to be dropped after moving it into the + // function. + { + let g = move || match drop($name::unsend::Client::default()) { + _status => yield, + }; + assert_send(g); + } + )* } } fn assert_send<T: Send>(_thing: T) {} -// This is the same bug as issue 57017, but using yield instead of await fn main() { - let client = Client; - let g = move || match status(&client) { - _status => yield, - }; - assert_send(g); + type_combinations!( + copy => { #[derive(Copy, Clone, Default)] pub struct Client; }; + derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; + significant_drop => { + #[derive(Default)] + pub struct Client; + impl Drop for Client { + fn drop(&mut self) {} + } + } + ); } diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index 83f068c207643..1d5b97e984fd1 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -33,11 +33,8 @@ LL | require_send(send_gen); note: required because it's used within this generator --> $DIR/issue-68112.rs:48:5 | -LL | / || { -LL | | yield; -LL | | t -LL | | } - | |_____^ +LL | || { + | ^^ note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>` --> $DIR/issue-68112.rs:45:30 | @@ -52,12 +49,8 @@ LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> note: required because it's used within this generator --> $DIR/issue-68112.rs:59:20 | -LL | let send_gen = || { - | ____________________^ -LL | | let _non_send_gen = make_non_send_generator2(); -LL | | yield; -LL | | }; - | |_____^ +LL | let send_gen = || { + | ^^ note: required by a bound in `require_send` --> $DIR/issue-68112.rs:22:25 | diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index edf9ee628a2bc..0b31bb4fdb1a0 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -9,13 +9,8 @@ LL | assert_send(|| { note: required because it's used within this generator --> $DIR/not-send-sync.rs:16:17 | -LL | assert_send(|| { - | _________________^ -LL | | -LL | | drop(&a); -LL | | yield; -LL | | }); - | |_____^ +LL | assert_send(|| { + | ^^ note: required by a bound in `assert_send` --> $DIR/not-send-sync.rs:7:23 | @@ -28,7 +23,7 @@ error: generator cannot be shared between threads safely LL | assert_sync(|| { | ^^^^^^^^^^^ generator is not `Sync` | - = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6]`, the trait `Sync` is not implemented for `Cell<i32>` + = help: within `[generator@$DIR/not-send-sync.rs:9:17: 9:19]`, the trait `Sync` is not implemented for `Cell<i32>` note: generator is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:12:9 | diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr index 16b34c917ece4..1004fc64da93a 100644 --- a/src/test/ui/generator/partial-drop.stderr +++ b/src/test/ui/generator/partial-drop.stderr @@ -4,7 +4,7 @@ error: generator cannot be sent between threads safely LL | assert_send(|| { | ^^^^^^^^^^^ generator is not `Send` | - = help: within `[generator@$DIR/partial-drop.rs:14:17: 20:6]`, the trait `Send` is not implemented for `Foo` + = help: within `[generator@$DIR/partial-drop.rs:14:17: 14:19]`, the trait `Send` is not implemented for `Foo` note: generator is not `Send` as this value is used across a yield --> $DIR/partial-drop.rs:19:9 | @@ -27,7 +27,7 @@ error: generator cannot be sent between threads safely LL | assert_send(|| { | ^^^^^^^^^^^ generator is not `Send` | - = help: within `[generator@$DIR/partial-drop.rs:22:17: 30:6]`, the trait `Send` is not implemented for `Foo` + = help: within `[generator@$DIR/partial-drop.rs:22:17: 22:19]`, the trait `Send` is not implemented for `Foo` note: generator is not `Send` as this value is used across a yield --> $DIR/partial-drop.rs:29:9 | @@ -50,7 +50,7 @@ error: generator cannot be sent between threads safely LL | assert_send(|| { | ^^^^^^^^^^^ generator is not `Send` | - = help: within `[generator@$DIR/partial-drop.rs:32:17: 39:6]`, the trait `Send` is not implemented for `Foo` + = help: within `[generator@$DIR/partial-drop.rs:32:17: 32:19]`, the trait `Send` is not implemented for `Foo` note: generator is not `Send` as this value is used across a yield --> $DIR/partial-drop.rs:38:9 | diff --git a/src/test/ui/generator/partial-initialization-across-yield.rs b/src/test/ui/generator/partial-initialization-across-yield.rs index 8b75721420351..65d9e6d39ca5a 100644 --- a/src/test/ui/generator/partial-initialization-across-yield.rs +++ b/src/test/ui/generator/partial-initialization-across-yield.rs @@ -9,8 +9,7 @@ struct T(i32, i32); fn test_tuple() { let _ = || { let mut t: (i32, i32); - t.0 = 42; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 42; //~ ERROR E0381 yield; t.1 = 88; let _ = t; @@ -20,8 +19,7 @@ fn test_tuple() { fn test_tuple_struct() { let _ = || { let mut t: T; - t.0 = 42; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 42; //~ ERROR E0381 yield; t.1 = 88; let _ = t; @@ -31,8 +29,7 @@ fn test_tuple_struct() { fn test_struct() { let _ = || { let mut t: S; - t.x = 42; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.x = 42; //~ ERROR E0381 yield; t.y = 88; let _ = t; diff --git a/src/test/ui/generator/partial-initialization-across-yield.stderr b/src/test/ui/generator/partial-initialization-across-yield.stderr index 66b86488eaec7..3f9f1c046ba4b 100644 --- a/src/test/ui/generator/partial-initialization-across-yield.stderr +++ b/src/test/ui/generator/partial-initialization-across-yield.stderr @@ -1,20 +1,32 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `t` +error[E0381]: partially assigned binding `t` isn't fully initialized --> $DIR/partial-initialization-across-yield.rs:12:9 | +LL | let mut t: (i32, i32); + | ----- binding declared here but left uninitialized LL | t.0 = 42; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/partial-initialization-across-yield.rs:23:9 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-yield.rs:22:9 | +LL | let mut t: T; + | ----- binding declared here but left uninitialized LL | t.0 = 42; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/partial-initialization-across-yield.rs:34:9 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/partial-initialization-across-yield.rs:32:9 | +LL | let mut t: S; + | ----- binding declared here but left uninitialized LL | t.x = 42; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error: aborting due to 3 previous errors diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr index 3ee4c1458bad3..5b61f1e8f2dc1 100644 --- a/src/test/ui/generator/print/generator-print-verbose-1.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -31,11 +31,8 @@ LL | require_send(send_gen); note: required because it's used within this generator --> $DIR/generator-print-verbose-1.rs:42:5 | -LL | / || { -LL | | yield; -LL | | t -LL | | } - | |_____^ +LL | || { + | ^^ note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])` --> $DIR/generator-print-verbose-1.rs:41:30 | @@ -50,12 +47,8 @@ LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> note: required because it's used within this generator --> $DIR/generator-print-verbose-1.rs:52:20 | -LL | let send_gen = || { - | ____________________^ -LL | | let _non_send_gen = make_non_send_generator2(); -LL | | yield; -LL | | }; - | |_____^ +LL | let send_gen = || { + | ^^ note: required by a bound in `require_send` --> $DIR/generator-print-verbose-1.rs:26:25 | diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr index 1356fa5f15295..eb79d2e6eedbd 100644 --- a/src/test/ui/generator/print/generator-print-verbose-2.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -9,13 +9,8 @@ LL | assert_send(|| { note: required because it's used within this generator --> $DIR/generator-print-verbose-2.rs:19:17 | -LL | assert_send(|| { - | _________________^ -LL | | -LL | | drop(&a); -LL | | yield; -LL | | }); - | |_____^ +LL | assert_send(|| { + | ^^ note: required by a bound in `assert_send` --> $DIR/generator-print-verbose-2.rs:10:23 | diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 4ae745b0ffeac..e3859595fd2ce 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,8 +1,8 @@ -error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` cannot be unpinned --> $DIR/static-not-unpin.rs:14:18 | LL | assert_unpin(generator); - | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` + | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` | | | required by a bound introduced by this call | diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index d78a5929a896d..7938fc8097cd2 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -12,7 +12,7 @@ note: return type inferred to be `Result<{integer}, _>` here LL | return Ok(6); | ^^^^^ -error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 15:6] as Generator>::Return == i32` +error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Generator<Return = i32> { diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.rs b/src/test/ui/generic-associated-types/bugs/issue-80626.rs index a637da6cf6fa7..14f27aff1ccd8 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-80626.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #80626 // This should pass, but it requires `Sized` to be coinductive. diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr index 8b0cc78e99949..487b83dfa3fcc 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr @@ -4,16 +4,11 @@ error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized` LL | Next(A::Allocated<Self>) | ^^^^^^^^^^^^^^^^^^ | - = note: no field of an enum variant may have a dynamically sized type - = help: change the field's type to have a statically known size -help: borrowed types always have a statically known size +note: required by a bound in `Allocator::Allocated` + --> $DIR/issue-80626.rs:9:20 | -LL | Next(&A::Allocated<Self>) - | + -help: the `Box` type always has a statically known size and allocates its contents in the heap - | -LL | Next(Box<A::Allocated<Self>>) - | ++++ + +LL | type Allocated<T>; + | ^ required by this bound in `Allocator::Allocated` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/bugs/issue-86218.rs index 68cd0fd7efce0..fb62c10a9e389 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #86218 // This should pass, but seems to run into a TAIT issue. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs index 53e3ad7fe6943..0844d84c34fd3 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87735.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #87735, #88526 // This should pass, but we need an extension of implied bounds (probably). diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs index 6e7cd45bdb1f6..a3d00ee03b13e 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87748.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87748.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #87748 // This should pass, but unnormalized input args aren't treated as implied. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr index 60bb48efbc895..ac197dfe6ff69 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr @@ -4,12 +4,12 @@ error[E0478]: lifetime bound not satisfied LL | fn do_sth(_: u32) {} | ^^^^^^^^^^^^^^^^^ | -note: lifetime parameter instantiated with the anonymous lifetime #2 defined here +note: lifetime parameter instantiated with the anonymous lifetime as defined here --> $DIR/issue-87748.rs:18:5 | LL | fn do_sth(_: u32) {} | ^^^^^^^^^^^^^^^^^ -note: but lifetime parameter must outlive the anonymous lifetime #1 defined here +note: but lifetime parameter must outlive the anonymous lifetime as defined here --> $DIR/issue-87748.rs:18:5 | LL | fn do_sth(_: u32) {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.rs b/src/test/ui/generic-associated-types/bugs/issue-87755.rs index 31cea12a3e241..efa487d624fd9 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87755.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #87755 // This should pass. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.rs b/src/test/ui/generic-associated-types/bugs/issue-87803.rs index 57a4b028d93ea..a8a111c99ef7f 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87803.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #87803 // This should pass, but using a type alias vs a reference directly // changes late-bound -> early-bound. diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.rs b/src/test/ui/generic-associated-types/bugs/issue-88382.rs index c9f342405278a..5493b9b939135 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88382.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #88382 // This should pass, but has a missed normalization due to HRTB. diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.rs b/src/test/ui/generic-associated-types/bugs/issue-88460.rs index b31d012d2fc41..f1c3b2269158a 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88460.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #88460 // This should pass, but has a missed normalization due to HRTB. diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.rs b/src/test/ui/generic-associated-types/bugs/issue-88526.rs index c72a450b9261c..15363ad04bfe7 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88526.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #88526 // This should pass, but requires more logic. diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/bugs/issue-89008.rs index 1581b7105a867..79c28b0d22172 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.rs @@ -1,6 +1,6 @@ // check-fail // edition:2021 -// known-bug +// known-bug: #88908 // This should pass, but seems to run into a TAIT bug. diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr index 5cbadfacc1b60..50844fdc14d94 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr @@ -1,10 +1,10 @@ error[E0271]: type mismatch resolving `<Empty<_> as Stream>::Item == Repr` - --> $DIR/issue-89008.rs:40:9 + --> $DIR/issue-89008.rs:39:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { - | ---- this type parameter -LL | async {empty()} - | ^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr` + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Empty<_> as Stream>::Item == Repr` + | | + | this type parameter | note: expected this to be `()` --> $DIR/issue-89008.rs:18:17 diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index 68594bba48632..c7ebb9880f710 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -14,10 +14,10 @@ error[E0276]: impl has stricter requirements than trait --> $DIR/generic-associated-types-where.rs:22:5 | LL | type Assoc3<T>; - | --------------- definition of `Assoc3` from trait + | -------------- definition of `Assoc3` from trait ... LL | type Assoc3<T> = Vec<T> where T: Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` + | ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 3d90471e398e6..6aa52b179a3c6 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -2,25 +2,25 @@ error: `impl` associated type signature for `A` doesn't match `trait` associated --> $DIR/impl_bounds.rs:15:5 | LL | type A<'a> where Self: 'a; - | -------------------------- expected + | ---------- expected ... LL | type A<'a> = (&'a ()) where Self: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + | ^^^^^^^^^^ found error: `impl` associated type signature for `B` doesn't match `trait` associated type signature --> $DIR/impl_bounds.rs:17:5 | LL | type B<'a, 'b> where 'a: 'b; - | ---------------------------- expected + | -------------- expected ... LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + | ^^^^^^^^^^^^^^ found error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:22 | LL | type B<'a, 'b> where 'a: 'b; - | ---------------------------- definition of `B` from trait + | -------------- definition of `B` from trait ... LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; | ^^^^^^^^^^^^^^^ - help: try copying this clause from the trait: `, 'a: 'b` @@ -40,7 +40,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:20:5 | LL | type C = String where Self: Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | note: required because of the requirements on the impl of `Copy` for `Fooy<T>` --> $DIR/impl_bounds.rs:11:10 @@ -54,7 +54,7 @@ LL | trait Foo { | --- in this trait ... LL | type C where Self: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ this trait associated type doesn't have the requirement `Fooy<T>: Copy` + | ^^^^^^ this trait associated type doesn't have the requirement `Fooy<T>: Copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index 39beac38c0b61..c560e2405d5a7 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -2,10 +2,10 @@ error[E0276]: impl has stricter requirements than trait --> $DIR/issue-47206-where-clause.rs:12:5 | LL | type Assoc3<T>; - | --------------- definition of `Assoc3` from trait + | -------------- definition of `Assoc3` from trait ... LL | type Assoc3<T> = Vec<T> where T: Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` + | ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr index c4a7d8faa4119..d487f19ba7490 100644 --- a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr +++ b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr @@ -45,7 +45,7 @@ note: ...does not necessarily outlive the static lifetime introduced by the comp --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:21:1 | LL | impl C for Box<dyn A + 'static> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: incompatible lifetime on type --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:18 diff --git a/src/test/ui/generic-associated-types/issue-79422.extended.stderr b/src/test/ui/generic-associated-types/issue-79422.extended.stderr index 9478fc8979211..9bcbd74716845 100644 --- a/src/test/ui/generic-associated-types/issue-79422.extended.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.extended.stderr @@ -27,7 +27,7 @@ LL | type VRefCont<'a> = &'a V where Self: 'a; | ^^^^^ = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` found reference `&u8` - = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>` + = note: required for the cast from `BTreeMap<u8, u8>` to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/issue-90014.stderr b/src/test/ui/generic-associated-types/issue-90014.stderr index 51fe3360c7eb2..457c582e8c8d8 100644 --- a/src/test/ui/generic-associated-types/issue-90014.stderr +++ b/src/test/ui/generic-associated-types/issue-90014.stderr @@ -2,7 +2,7 @@ error[E0477]: the type `&mut ()` does not fulfill the required lifetime --> $DIR/issue-90014.rs:14:20 | LL | type Fut<'a> where Self: 'a; - | ---------------------------- definition of `Fut` from trait + | ------------ definition of `Fut` from trait ... LL | type Fut<'a> = impl Future<Output = ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a` diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs index 092fa939c308d..40eef11f058e1 100644 --- a/src/test/ui/generic-associated-types/issue-91139.rs +++ b/src/test/ui/generic-associated-types/issue-91139.rs @@ -22,6 +22,7 @@ fn foo<T>() { //~| ERROR `T` does not live long enough //~| ERROR `T` does not live long enough //~| ERROR `T` does not live long enough + //~| ERROR `T` may not live long enough // // FIXME: This error is bogus, but it arises because we try to validate // that `<() as Foo<T>>::Type<'a>` is valid, which requires proving diff --git a/src/test/ui/generic-associated-types/issue-91139.stderr b/src/test/ui/generic-associated-types/issue-91139.stderr index 6c5092978c84b..b789b3a42f330 100644 --- a/src/test/ui/generic-associated-types/issue-91139.stderr +++ b/src/test/ui/generic-associated-types/issue-91139.stderr @@ -34,6 +34,17 @@ error: `T` does not live long enough LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue-91139.rs:16:58 + | +LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| (); + | ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo<T: 'static>() { + | +++++++++ + error: `T` does not live long enough --> $DIR/issue-91139.rs:16:58 | @@ -46,5 +57,6 @@ error: `T` does not live long enough LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/generic-associated-types/issue-91883.rs b/src/test/ui/generic-associated-types/issue-91883.rs new file mode 100644 index 0000000000000..3d4585a44df80 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-91883.rs @@ -0,0 +1,42 @@ +#![feature(generic_associated_types)] + +use std::fmt::Debug; +use std::marker::PhantomData; + +#[derive(Debug)] +pub struct TransactionImpl<'db> { + _marker: PhantomData<&'db ()>, +} + +#[derive(Debug)] +pub struct CursorImpl<'txn> { + _marker: PhantomData<&'txn ()>, +} + +pub trait Cursor<'txn> {} + +pub trait Transaction<'db>: Send + Sync + Debug + Sized { + type Cursor<'tx>: Cursor<'tx> + where + 'db: 'tx, + Self: 'tx; + + fn cursor<'tx>(&'tx self) -> Result<Self::Cursor<'tx>, ()> + where + 'db: 'tx; +} + +impl<'tx> Cursor<'tx> for CursorImpl<'tx> {} + +impl<'db> Transaction<'db> for TransactionImpl<'db> { + type Cursor<'tx> = CursorImpl<'tx>; //~ ERROR lifetime bound not satisfied + + fn cursor<'tx>(&'tx self) -> Result<Self::Cursor<'tx>, ()> + where + 'db: 'tx, + { + loop {} + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-91883.stderr b/src/test/ui/generic-associated-types/issue-91883.stderr new file mode 100644 index 0000000000000..baf4889cc1dd5 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-91883.stderr @@ -0,0 +1,23 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/issue-91883.rs:32:24 + | +LL | type Cursor<'tx>: Cursor<'tx> + | ----------------------------- definition of `Cursor` from trait +... +LL | type Cursor<'tx> = CursorImpl<'tx>; + | ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx` + | +note: lifetime parameter instantiated with the lifetime `'db` as defined here + --> $DIR/issue-91883.rs:31:6 + | +LL | impl<'db> Transaction<'db> for TransactionImpl<'db> { + | ^^^ +note: but lifetime parameter must outlive the lifetime `'tx` as defined here + --> $DIR/issue-91883.rs:32:17 + | +LL | type Cursor<'tx> = CursorImpl<'tx>; + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0478`. diff --git a/src/test/ui/generic-associated-types/issue-92033.stderr b/src/test/ui/generic-associated-types/issue-92033.stderr index 5b90199b8091f..6dd901027d7ba 100644 --- a/src/test/ui/generic-associated-types/issue-92033.stderr +++ b/src/test/ui/generic-associated-types/issue-92033.stderr @@ -1,13 +1,11 @@ error[E0477]: the type `&'s Texture` does not fulfill the required lifetime --> $DIR/issue-92033.rs:22:28 | -LL | / type TextureIter<'a>: Iterator<Item = &'a Texture> -LL | | where -LL | | Self: 'a; - | |_________________- definition of `TextureIter` from trait +LL | type TextureIter<'a>: Iterator<Item = &'a Texture> + | -------------------------------------------------- definition of `TextureIter` from trait ... -LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a` +LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a` | note: type must outlive the lifetime `'a` as defined here --> $DIR/issue-92033.rs:22:22 diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs index 2365daada1147..e2f1710fa281c 100644 --- a/src/test/ui/generic-associated-types/issue-95305.rs +++ b/src/test/ui/generic-associated-types/issue-95305.rs @@ -3,7 +3,7 @@ // at some point in the future. #![feature(generic_associated_types)] - +#![feature(anonymous_lifetime_in_impl_trait)] trait Foo { type Item<'a>; } @@ -11,7 +11,10 @@ trait Foo { fn foo(x: &impl Foo<Item<'_> = u32>) { } //~^ ERROR `'_` cannot be used here [E0637] +// Ok: the anonymous lifetime is bound to the function. fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { } - //~^ ERROR missing lifetime specifier + +// Ok: the anonymous lifetime is bound to the function. +fn baz(x: &impl for<'a> Foo<Item<'a> = &u32>) { } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr index 8624d880d4ee2..d8557525f54ed 100644 --- a/src/test/ui/generic-associated-types/issue-95305.stderr +++ b/src/test/ui/generic-associated-types/issue-95305.stderr @@ -4,18 +4,6 @@ error[E0637]: `'_` cannot be used here LL | fn foo(x: &impl Foo<Item<'_> = u32>) { } | ^^ `'_` is a reserved lifetime name -error[E0106]: missing lifetime specifier - --> $DIR/issue-95305.rs:14:41 - | -LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { } - | ^^ expected named lifetime parameter - | -help: consider using the `'a` lifetime - | -LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'a u32>) { } - | ~~ - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0106, E0637. -For more information about an error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr index 9eeebd80afecb..d9dc77ac8eb40 100644 --- a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr @@ -2,9 +2,9 @@ error[E0599]: the method `f` exists for struct `S`, but its trait bounds were no --> $DIR/method-unsatified-assoc-type-predicate.rs:30:7 | LL | struct S; - | --------- + | -------- | | - | method `f` not found for this + | method `f` not found for this struct | doesn't satisfy `<S as X>::Y<i32> = i32` | doesn't satisfy `S: M` ... diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed new file mode 100644 index 0000000000000..2315810a47ace --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -0,0 +1,46 @@ +// run-rustfix + +use std::ops::Add; + +struct A<B>(B); + +impl<B> Add for A<B> where B: Add + Add<Output = B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + A(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +struct C<B>(B); + +impl<B: Add + Add<Output = B>> Add for C<B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +struct D<B>(B); + +impl<B: std::ops::Add<Output=B>> Add for D<B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR cannot add `B` to `B` + } +} + +struct E<B>(B); + +impl<B: Add + Add<Output = B>> Add for E<B> where B: Add<Output = B> { + //~^ ERROR equality constraints are not yet supported in `where` clauses + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs index b3661ba3744ee..ffafff5e9f586 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.rs +++ b/src/test/ui/generic-associated-types/missing-bounds.rs @@ -1,3 +1,5 @@ +// run-rustfix + use std::ops::Add; struct A<B>(B); diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 5323ee172267f..138c642dd7952 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -1,5 +1,5 @@ error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:35:33 + --> $DIR/missing-bounds.rs:37:33 | LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B { | ^^^^^^^^^^^^^^^^^^^^^^ not supported @@ -11,7 +11,7 @@ LL | impl<B: Add> Add for E<B> where B: Add<Output = B> { | ~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:9:11 + --> $DIR/missing-bounds.rs:11:11 | LL | impl<B> Add for A<B> where B: Add { | - this type parameter @@ -24,7 +24,7 @@ LL | A(self.0 + rhs.0) = note: expected type parameter `B` found associated type `<B as Add>::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:3:8 + --> $DIR/missing-bounds.rs:5:8 | LL | struct A<B>(B); | ^ @@ -34,7 +34,7 @@ LL | impl<B> Add for A<B> where B: Add + Add<Output = B> { | +++++++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:19:14 + --> $DIR/missing-bounds.rs:21:14 | LL | impl<B: Add> Add for C<B> { | - this type parameter @@ -47,7 +47,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `<B as Add>::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:13:8 + --> $DIR/missing-bounds.rs:15:8 | LL | struct C<B>(B); | ^ @@ -57,7 +57,7 @@ LL | impl<B: Add + Add<Output = B>> Add for C<B> { | +++++++++++++++++ error[E0369]: cannot add `B` to `B` - --> $DIR/missing-bounds.rs:29:21 + --> $DIR/missing-bounds.rs:31:21 | LL | Self(self.0 + rhs.0) | ------ ^ ----- B @@ -66,11 +66,11 @@ LL | Self(self.0 + rhs.0) | help: consider restricting type parameter `B` | -LL | impl<B: std::ops::Add> Add for D<B> { - | +++++++++++++++ +LL | impl<B: std::ops::Add<Output=B>> Add for D<B> { + | +++++++++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:40:14 + --> $DIR/missing-bounds.rs:42:14 | LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B { | - this type parameter @@ -83,7 +83,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `<B as Add>::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:33:8 + --> $DIR/missing-bounds.rs:35:8 | LL | struct E<B>(B); | ^ diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr index 9e0896127a8a3..0256d2f20fc1e 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -2,10 +2,10 @@ error: `impl` associated type signature for `Assoc` doesn't match `trait` associ --> $DIR/missing-where-clause-on-trait.rs:9:5 | LL | type Assoc<'a, 'b>; - | ------------------- expected + | ------------------ expected ... LL | type Assoc<'a, 'b> = () where 'a: 'b; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found + | ^^^^^^^^^^^^^^^^^^ found error: aborting due to previous error diff --git a/src/test/ui/generics/issue-94432-garbage-ice.rs b/src/test/ui/generics/issue-94432-garbage-ice.rs new file mode 100644 index 0000000000000..d0709e2d2a46c --- /dev/null +++ b/src/test/ui/generics/issue-94432-garbage-ice.rs @@ -0,0 +1,10 @@ +// check-fail +// dont-check-compiler-stdout +// dont-check-compiler-stderr + +fn�a<e>(){fn�p(){e}} //~ ERROR unknown start of token: \u{fffd} +//~^ ERROR unknown start of token: \u{fffd} +//~^^ ERROR can't use generic parameters from outer function [E0401] +//~^^^ WARN type parameter `e` should have an upper camel case name + +fn main(){} diff --git a/src/test/ui/generics/issue-98432.rs b/src/test/ui/generics/issue-98432.rs new file mode 100644 index 0000000000000..780c50d6ffa19 --- /dev/null +++ b/src/test/ui/generics/issue-98432.rs @@ -0,0 +1,9 @@ +struct Struct<T>(T); + +impl<T> Struct<T> { + const CONST: fn() = || { + struct _Obligation where T:; //~ ERROR can't use generic parameters from outer function + }; +} + +fn main() {} diff --git a/src/test/ui/generics/issue-98432.stderr b/src/test/ui/generics/issue-98432.stderr new file mode 100644 index 0000000000000..afa67b63bd9a1 --- /dev/null +++ b/src/test/ui/generics/issue-98432.stderr @@ -0,0 +1,14 @@ +error[E0401]: can't use generic parameters from outer function + --> $DIR/issue-98432.rs:5:34 + | +LL | impl<T> Struct<T> { + | - type parameter from outer function +LL | const CONST: fn() = || { +LL | struct _Obligation where T:; + | ^ use of generic parameter from outer function + | + = help: try using a local generic parameter instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0401`. diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr index 15e83ab5a347d..c01ab8e347c6c 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr @@ -4,7 +4,7 @@ error: higher-ranked lifetime error LL | v.t(|| {}); | ^^^^^^^^^^ | - = note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed + = note: could not prove `[closure@$DIR/issue-59311.rs:17:9: 17:11] well-formed` error: higher-ranked lifetime error --> $DIR/issue-59311.rs:17:9 @@ -12,7 +12,7 @@ error: higher-ranked lifetime error LL | v.t(|| {}); | ^^^^^ | - = note: could not prove for<'a> &'a V: 'static + = note: could not prove `for<'a> &'a V: 'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr index 0bfa7b3cc7c45..eebce827d1cae 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr @@ -10,7 +10,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/issue-71955.rs:25:9 | @@ -29,7 +29,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/issue-71955.rs:25:44 | @@ -48,7 +48,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/issue-71955.rs:25:9 | @@ -67,7 +67,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/issue-71955.rs:25:44 | diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr index 7f45fb83cef08..a6858154dfb29 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr @@ -19,44 +19,44 @@ LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied - --> $DIR/issue-89118.rs:22:20 + --> $DIR/issue-89118.rs:29:9 | -LL | type Handler = Ctx<C::Dispatcher>; - | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` +LL | impl<C> EthernetWorker<C> {} + | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` --> $DIR/issue-89118.rs:5:23 | LL | impl<B: BufferMut, C> BufferUdpStateContext<B> for C {} | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ -note: required by a bound in `StackContext` - --> $DIR/issue-89118.rs:9:14 +note: required by a bound in `EthernetWorker` + --> $DIR/issue-89118.rs:28:14 | -LL | trait StackContext - | ------------ required by a bound in this +LL | struct EthernetWorker<C>(C) + | -------------- required by a bound in this LL | where -LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EthernetWorker` error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied - --> $DIR/issue-89118.rs:29:9 + --> $DIR/issue-89118.rs:22:20 | -LL | impl<C> EthernetWorker<C> {} - | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` +LL | type Handler = Ctx<C::Dispatcher>; + | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` --> $DIR/issue-89118.rs:5:23 | LL | impl<B: BufferMut, C> BufferUdpStateContext<B> for C {} | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ -note: required by a bound in `EthernetWorker` - --> $DIR/issue-89118.rs:28:14 +note: required by a bound in `StackContext` + --> $DIR/issue-89118.rs:9:14 | -LL | struct EthernetWorker<C>(C) - | -------------- required by a bound in this +LL | trait StackContext + | ------------ required by a bound in this LL | where -LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EthernetWorker` +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` error: aborting due to 3 previous errors diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs new file mode 100644 index 0000000000000..f7e467b3786dc --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs @@ -0,0 +1,44 @@ +// check-pass + +#![allow(unused)] + +trait MiniYokeable<'a> { + type Output; +} + +struct MiniYoke<Y: for<'a> MiniYokeable<'a>> { + pub yokeable: Y, +} + +fn map_project_broken<Y, P>( + source: MiniYoke<Y>, + f: impl for<'a> FnOnce( + <Y as MiniYokeable<'a>>::Output, + core::marker::PhantomData<&'a ()>, + ) -> <P as MiniYokeable<'a>>::Output, +) -> MiniYoke<P> +where + Y: for<'a> MiniYokeable<'a>, + P: for<'a> MiniYokeable<'a> +{ + unimplemented!() +} + +struct Bar<'a> { + string_1: &'a str, + string_2: &'a str, +} + +impl<'a> MiniYokeable<'a> for Bar<'static> { + type Output = Bar<'a>; +} + +impl<'a> MiniYokeable<'a> for &'static str { + type Output = &'a str; +} + +fn demo_broken(bar: MiniYoke<Bar<'static>>) -> MiniYoke<&'static str> { + map_project_broken(bar, |bar, _| bar.string_1) +} + +fn main() {} diff --git a/src/test/ui/hrtb/issue-30786.stderr b/src/test/ui/hrtb/issue-30786.stderr index 1ee549e54a908..bc7b5e914e127 100644 --- a/src/test/ui/hrtb/issue-30786.stderr +++ b/src/test/ui/hrtb/issue-30786.stderr @@ -1,19 +1,19 @@ -error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>`, but its trait bounds were not satisfied +error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:118:22 | LL | pub struct Map<S, F> { | -------------------- | | - | method `filterx` not found for this + | method `filterx` not found for this struct | doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: - `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>: Stream` - `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>: Stream` - `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>: Stream` + `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream` + `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream` + `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream` --> $DIR/issue-30786.rs:96:50 | LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {} @@ -23,22 +23,22 @@ help: one of the expressions' fields has a method of the same name LL | let filter = map.stream.filterx(|x: &_| true); | +++++++ -error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>`, but its trait bounds were not satisfied +error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:130:24 | LL | pub struct Filter<S, F> { | ----------------------- | | - | method `countx` not found for this + | method `countx` not found for this struct | doesn't satisfy `_: StreamExt` ... LL | let count = filter.countx(); - | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>` due to unsatisfied trait bounds + | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: - `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>: Stream` - `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>: Stream` - `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>: Stream` + `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream` + `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream` + `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream` --> $DIR/issue-30786.rs:96:50 | LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {} diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index 0ebba37e4ec70..79ef56b9fa5cb 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` +error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` --> $DIR/issue-62203-hrtb-ice.rs:38:19 | LL | let v = Unit2.m( - | ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` + | ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` | note: expected this to be `<_ as Ty<'_>>::V` --> $DIR/issue-62203-hrtb-ice.rs:21:14 @@ -22,7 +22,7 @@ LL | where LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>, | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&'r u8,),)>>::Output == Unit3` +error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3` --> $DIR/issue-62203-hrtb-ice.rs:40:9 | LL | let v = Unit2.m( @@ -34,7 +34,7 @@ LL | | f : |x| { drop(x); Unit4 } LL | | }); | |_________^ expected struct `Unit3`, found struct `Unit4` | -note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]>` +note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>` --> $DIR/issue-62203-hrtb-ice.rs:17:16 | LL | impl<'a, A, T> T0<'a, A> for L<T> diff --git a/src/test/ui/hrtb/issue-95034.rs b/src/test/ui/hrtb/issue-95034.rs index aee6fe61ba812..d8edbe7e56b51 100644 --- a/src/test/ui/hrtb/issue-95034.rs +++ b/src/test/ui/hrtb/issue-95034.rs @@ -1,4 +1,4 @@ -// known-bug +// known-bug: #95034 // failure-status: 101 // compile-flags: --edition=2021 --crate-type=lib // rustc-env:RUST_BACKTRACE=0 diff --git a/src/test/ui/impl-duplicate-methods.stderr b/src/test/ui/impl-duplicate-methods.stderr index b6dc4882fc8f3..c19702a5bf0cf 100644 --- a/src/test/ui/impl-duplicate-methods.stderr +++ b/src/test/ui/impl-duplicate-methods.stderr @@ -2,9 +2,9 @@ error[E0201]: duplicate definitions with name `orange`: --> $DIR/impl-duplicate-methods.rs:5:5 | LL | fn orange(&self) {} - | ------------------- previous definition of `orange` here + | ---------------- previous definition of `orange` here LL | fn orange(&self) {} - | ^^^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index d2452abab0254..c2fbbf94fd666 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -11,7 +11,6 @@ fn main() { // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { //~^ ERROR cycle detected - //~| ERROR cycle detected send(cycle2().clone()); Rc::new(Cell::new(5)) diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 14db864f1c28a..634ff14869eb4 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -30,129 +30,47 @@ note: ...which requires building MIR for `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:20:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/auto-trait-leak.rs:1:1 - | -LL | / use std::cell::Cell; -LL | | use std::rc::Rc; -LL | | -LL | | fn send<T: Send>(_: T) {} -... | -LL | | Rc::new(String::from("foo")) -LL | | } - | |_^ - -error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:12:16 + --> $DIR/auto-trait-leak.rs:14:5 | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires borrow-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | send(cycle2().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:20:16 + --> $DIR/auto-trait-leak.rs:19:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:19:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:1 + --> $DIR/auto-trait-leak.rs:20:5 | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | send(cycle1().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 @@ -166,6 +84,6 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index d825843492d49..52fa28145d664 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -14,7 +14,7 @@ note: required because it's used within this closure --> $DIR/auto-trait-leak2.rs:10:5 | LL | move |x| p.set(x) - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ note: required because it appears within the type `impl Fn(i32)` --> $DIR/auto-trait-leak2.rs:5:16 | @@ -42,7 +42,7 @@ note: required because it's used within this closure --> $DIR/auto-trait-leak2.rs:38:5 | LL | move |x| p.set(x) - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ note: required because it appears within the type `impl Fn(i32)` --> $DIR/auto-trait-leak2.rs:33:15 | diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr index 3b360f492b70e..5e10272b0db3c 100644 --- a/src/test/ui/impl-trait/auto-trait.stderr +++ b/src/test/ui/impl-trait/auto-trait.stderr @@ -1,3 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + --> $DIR/auto-trait.rs:21:1 + | +LL | impl<T: Send> AnotherTrait for T {} + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D<OpaqueType> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + error: cannot implement trait on type alias impl trait --> $DIR/auto-trait.rs:21:25 | @@ -10,15 +19,6 @@ note: type alias impl trait defined here LL | type OpaqueType = impl OpaqueTrait; | ^^^^^^^^^^^^^^^^ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` - --> $DIR/auto-trait.rs:21:1 - | -LL | impl<T: Send> AnotherTrait for T {} - | -------------------------------- first implementation here -... -LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr index 11ba5aa7867fe..957052feba95b 100644 --- a/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr +++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr @@ -3,16 +3,12 @@ error[E0282]: type annotations needed | LL | cont.reify_as(); | ^^^^ cannot infer type - | - = note: type must be known at this point error[E0282]: type annotations needed --> $DIR/hidden-type-is-opaque-2.rs:18:9 | LL | cont.reify_as(); | ^^^^ cannot infer type - | - = note: type must be known at this point error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs index a75b9b43b3e8b..22ff7ffa23cb3 100644 --- a/src/test/ui/impl-trait/issue-55872-1.rs +++ b/src/test/ui/impl-trait/issue-55872-1.rs @@ -11,9 +11,9 @@ impl<S: Default> Bar for S { fn foo<T: Default>() -> Self::E { //~^ ERROR impl has stricter requirements than trait - (S::default(), T::default()) - //~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] + //~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] + (S::default(), T::default()) } } diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index efc57da746132..8912cce1b4b5b 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -8,10 +8,10 @@ LL | fn foo<T: Default>() -> Self::E { | ^^^^^^^ impl has extra requirement `T: Default` error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:14:9 + --> $DIR/issue-55872-1.rs:12:29 | -LL | (S::default(), T::default()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` +LL | fn foo<T: Default>() -> Self::E { + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound @@ -20,10 +20,10 @@ LL | impl<S: Default + std::marker::Copy> Bar for S { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:14:9 + --> $DIR/issue-55872-1.rs:12:29 | -LL | (S::default(), T::default()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` +LL | fn foo<T: Default>() -> Self::E { + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound diff --git a/src/test/ui/impl-trait/issue-55872-3.rs b/src/test/ui/impl-trait/issue-55872-3.rs index 36d9fdede109e..3ffce85e61ba4 100644 --- a/src/test/ui/impl-trait/issue-55872-3.rs +++ b/src/test/ui/impl-trait/issue-55872-3.rs @@ -12,8 +12,8 @@ pub trait Bar { impl<S> Bar for S { type E = impl std::marker::Copy; fn foo<T>() -> Self::E { + //~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied [E0277] async {} - //~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/impl-trait/issue-55872-3.stderr b/src/test/ui/impl-trait/issue-55872-3.stderr index e7023e8127c3d..6ab540e875162 100644 --- a/src/test/ui/impl-trait/issue-55872-3.stderr +++ b/src/test/ui/impl-trait/issue-55872-3.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `impl Future<Output = ()>: Copy` is not satisfied - --> $DIR/issue-55872-3.rs:15:9 + --> $DIR/issue-55872-3.rs:14:20 | -LL | async {} - | ^^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = ()>` +LL | fn foo<T>() -> Self::E { + | ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = ()>` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr index 64cce056a2688..9150d957db76d 100644 --- a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr +++ b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `foo` found for struct `Bar` in the current scope --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:20:8 | LL | struct Bar; - | ----------- method `foo` not found for this + | ---------- method `foo` not found for this struct ... LL | f1.foo(1usize); | ^^^ method not found in `Bar` diff --git a/src/test/ui/impl-trait/issues/issue-62742.stderr b/src/test/ui/impl-trait/issues/issue-62742.stderr index 70d693b8bee95..34f4dc2cef37d 100644 --- a/src/test/ui/impl-trait/issues/issue-62742.stderr +++ b/src/test/ui/impl-trait/issues/issue-62742.stderr @@ -18,20 +18,18 @@ LL | WrongImpl::<()>::foo(0i32); | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds ... LL | pub struct RawImpl<T>(PhantomData<T>); - | -------------------------------------- doesn't satisfy `RawImpl<()>: Raw<()>` + | --------------------- doesn't satisfy `RawImpl<()>: Raw<()>` ... LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>); - | --------------------------------------------------------------- function or associated item `foo` not found for this + | ----------------------------------------- function or associated item `foo` not found for this struct | = note: the following trait bounds were not satisfied: `RawImpl<()>: Raw<()>` note: the following trait must be implemented --> $DIR/issue-62742.rs:12:1 | -LL | / pub trait Raw<T: ?Sized> { -LL | | type Value; -LL | | } - | |_^ +LL | pub trait Raw<T: ?Sized> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied --> $DIR/issue-62742.rs:6:5 diff --git a/src/test/ui/impl-trait/issues/issue-70877.rs b/src/test/ui/impl-trait/issues/issue-70877.rs index 1a86fa00ed1a0..8169cfafac711 100644 --- a/src/test/ui/impl-trait/issues/issue-70877.rs +++ b/src/test/ui/impl-trait/issues/issue-70877.rs @@ -13,7 +13,7 @@ impl Iterator for Bar { type Item = FooItem; fn next(&mut self) -> Option<Self::Item> { - Some(Box::new(quux)) //~ ERROR mismatched types + Some(Box::new(quux)) } } diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr index 7cbd58bdabf2f..8813bff3c353e 100644 --- a/src/test/ui/impl-trait/issues/issue-70877.stderr +++ b/src/test/ui/impl-trait/issues/issue-70877.stderr @@ -1,17 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-70877.rs:16:9 - | -LL | type FooRet = impl std::fmt::Debug; - | -------------------- the expected opaque type -... -LL | fn next(&mut self) -> Option<Self::Item> { - | ------------------ expected `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>` because of return type -LL | Some(Box::new(quux)) - | ^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found fn item - | - = note: expected enum `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>` - found enum `Option<Box<for<'r> fn(&'r (dyn ToString + 'r)) -> FooRet {quux}>>` - error: opaque type's hidden type cannot be another opaque type from the same scope --> $DIR/issue-70877.rs:31:12 | @@ -29,6 +15,5 @@ note: opaque type being used as hidden type LL | type FooRet = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/issues/issue-74282.stderr b/src/test/ui/impl-trait/issues/issue-74282.stderr index 0f855ef57927a..5b05fb2810dff 100644 --- a/src/test/ui/impl-trait/issues/issue-74282.stderr +++ b/src/test/ui/impl-trait/issues/issue-74282.stderr @@ -13,7 +13,7 @@ LL | | }) | |_____^ expected closure, found a different closure | = note: expected opaque type `Closure` - found closure `[closure@$DIR/issue-74282.rs:8:15: 10:6]` + found closure `[closure@$DIR/issue-74282.rs:8:15: 8:17]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object note: tuple struct defined here diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs index 5498793bc28da..002e4cde40abe 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.rs +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -7,7 +7,8 @@ type F = impl core::future::Future<Output = u8>; struct Bug { V1: [(); { fn concrete_use() -> F { - async {} //~ ERROR type mismatch + //~^ ERROR type mismatch + async {} } let f: F = async { 1 }; //~^ ERROR `async` blocks are not allowed in constants diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index 7a057c7f51b8c..690d6abc76663 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -1,5 +1,5 @@ error[E0658]: `async` blocks are not allowed in constants - --> $DIR/issue-78722.rs:12:20 + --> $DIR/issue-78722.rs:13:20 | LL | let f: F = async { 1 }; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let f: F = async { 1 }; = help: add `#![feature(const_async_blocks)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/issue-78722.rs:12:13 + --> $DIR/issue-78722.rs:13:13 | LL | let f: F = async { 1 }; | ^ constants cannot evaluate destructors @@ -17,10 +17,10 @@ LL | }], | - value is dropped here error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8` - --> $DIR/issue-78722.rs:10:13 + --> $DIR/issue-78722.rs:9:30 | -LL | async {} - | ^^^^^^^^ expected `()`, found `u8` +LL | fn concrete_use() -> F { + | ^ expected `()`, found `u8` error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/issues/issue-83919.rs b/src/test/ui/impl-trait/issues/issue-83919.rs index 58aca77fdf19f..e76443a65dbf9 100644 --- a/src/test/ui/impl-trait/issues/issue-83919.rs +++ b/src/test/ui/impl-trait/issues/issue-83919.rs @@ -19,8 +19,9 @@ impl Foo for Implementor { type Fut = impl Future<Output=Self::Fut2>; fn get_fut(&self) -> Self::Fut { + //~^ ERROR `{integer}` is not a future async move { - 42 //~^ ERROR `{integer}` is not a future + 42 // 42 does not impl Future and rustc does actually point out the error, // but rustc used to panic. // Putting a valid Future here always worked fine. diff --git a/src/test/ui/impl-trait/issues/issue-83919.stderr b/src/test/ui/impl-trait/issues/issue-83919.stderr index ebd0130be8d06..d39dcf7fbf5d9 100644 --- a/src/test/ui/impl-trait/issues/issue-83919.stderr +++ b/src/test/ui/impl-trait/issues/issue-83919.stderr @@ -1,13 +1,8 @@ error[E0277]: `{integer}` is not a future - --> $DIR/issue-83919.rs:22:9 + --> $DIR/issue-83919.rs:21:26 | -LL | / async move { -LL | | 42 -LL | | // 42 does not impl Future and rustc does actually point out the error, -LL | | // but rustc used to panic. -LL | | // Putting a valid Future here always worked fine. -LL | | } - | |_________^ `{integer}` is not a future +LL | fn get_fut(&self) -> Self::Fut { + | ^^^^^^^^^ `{integer}` is not a future | = help: the trait `Future` is not implemented for `{integer}` = note: {integer} must be a future or must implement `IntoFuture` to be awaited diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index f6bb52bf6387c..b727b2ca0cce3 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `is_empty` found for struct `Foo` in the current s --> $DIR/method-suggestion-no-duplication.rs:7:15 | LL | struct Foo; - | ----------- method `is_empty` not found for this + | ---------- method `is_empty` not found for this struct ... LL | foo(|s| s.is_empty()); | ^^^^^^^^ method not found in `Foo` diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index f8ff2177bf5ac..586563c39061e 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -100,7 +100,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/must_outlive_least_region_or_bound.rs:38:5 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { - | -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:31]` captures the lifetime `'b` as defined here + | -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here LL | move |_| println!("{}", y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr index 98f9fbd8fefb7..479b451855d55 100644 --- a/src/test/ui/impl-trait/negative-reasoning.stderr +++ b/src/test/ui/impl-trait/negative-reasoning.stderr @@ -1,3 +1,14 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + --> $DIR/negative-reasoning.rs:19:1 + | +LL | impl<T: std::fmt::Debug> AnotherTrait for T {} + | ------------------------------------------- first implementation here +... +LL | impl AnotherTrait for D<OpaqueType> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + | + = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions + error: cannot implement trait on type alias impl trait --> $DIR/negative-reasoning.rs:19:25 | @@ -10,17 +21,6 @@ note: type alias impl trait defined here LL | type OpaqueType = impl OpaqueTrait; | ^^^^^^^^^^^^^^^^ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` - --> $DIR/negative-reasoning.rs:19:1 - | -LL | impl<T: std::fmt::Debug> AnotherTrait for T {} - | ------------------------------------------- first implementation here -... -LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` - | - = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/nested-return-type2-tait.stderr b/src/test/ui/impl-trait/nested-return-type2-tait.stderr index 359fb909e5418..1079a86ce9e73 100644 --- a/src/test/ui/impl-trait/nested-return-type2-tait.stderr +++ b/src/test/ui/impl-trait/nested-return-type2-tait.stderr @@ -5,7 +5,7 @@ LL | fn foo() -> impl Trait<Assoc = Sendable> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `Sendable` | = help: the trait `Duh` is implemented for `i32` -note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:27:5: 27:10]` +note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:27:5: 27:7]` --> $DIR/nested-return-type2-tait.rs:14:31 | LL | impl<R: Duh, F: FnMut() -> R> Trait for F { diff --git a/src/test/ui/impl-trait/nested-return-type2-tait2.rs b/src/test/ui/impl-trait/nested-return-type2-tait2.rs index af8e066305471..fcc077ec18ece 100644 --- a/src/test/ui/impl-trait/nested-return-type2-tait2.rs +++ b/src/test/ui/impl-trait/nested-return-type2-tait2.rs @@ -24,8 +24,8 @@ type Traitable = impl Trait<Assoc = Sendable>; // var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque // type does not implement `Duh`, even if its hidden type does. So we error out. fn foo() -> Traitable { - || 42 //~^ ERROR `Sendable: Duh` is not satisfied + || 42 } fn main() { diff --git a/src/test/ui/impl-trait/nested-return-type2-tait2.stderr b/src/test/ui/impl-trait/nested-return-type2-tait2.stderr index 42e65e692488d..847b940008531 100644 --- a/src/test/ui/impl-trait/nested-return-type2-tait2.stderr +++ b/src/test/ui/impl-trait/nested-return-type2-tait2.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Sendable: Duh` is not satisfied - --> $DIR/nested-return-type2-tait2.rs:27:5 + --> $DIR/nested-return-type2-tait2.rs:26:13 | -LL | || 42 - | ^^^^^ the trait `Duh` is not implemented for `Sendable` +LL | fn foo() -> Traitable { + | ^^^^^^^^^ the trait `Duh` is not implemented for `Sendable` | = help: the trait `Duh` is implemented for `i32` -note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait2.rs:27:5: 27:10]` +note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait2.rs:28:5: 28:7]` --> $DIR/nested-return-type2-tait2.rs:14:31 | LL | impl<R: Duh, F: FnMut() -> R> Trait for F { diff --git a/src/test/ui/impl-trait/nested-return-type2-tait3.rs b/src/test/ui/impl-trait/nested-return-type2-tait3.rs index 74fd8a9dda0bf..665c7a8cab91f 100644 --- a/src/test/ui/impl-trait/nested-return-type2-tait3.rs +++ b/src/test/ui/impl-trait/nested-return-type2-tait3.rs @@ -23,8 +23,8 @@ type Traitable = impl Trait<Assoc = impl Send>; // var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque // type does not implement `Duh`, even if its hidden type does. So we error out. fn foo() -> Traitable { - || 42 //~^ ERROR `impl Send: Duh` is not satisfied + || 42 } fn main() { diff --git a/src/test/ui/impl-trait/nested-return-type2-tait3.stderr b/src/test/ui/impl-trait/nested-return-type2-tait3.stderr index 4d3691d0e07fa..7b7f06b8e13e1 100644 --- a/src/test/ui/impl-trait/nested-return-type2-tait3.stderr +++ b/src/test/ui/impl-trait/nested-return-type2-tait3.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `impl Send: Duh` is not satisfied - --> $DIR/nested-return-type2-tait3.rs:26:5 + --> $DIR/nested-return-type2-tait3.rs:25:13 | -LL | || 42 - | ^^^^^ the trait `Duh` is not implemented for `impl Send` +LL | fn foo() -> Traitable { + | ^^^^^^^^^ the trait `Duh` is not implemented for `impl Send` | = help: the trait `Duh` is implemented for `i32` -note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait3.rs:26:5: 26:10]` +note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait3.rs:27:5: 27:7]` --> $DIR/nested-return-type2-tait3.rs:14:31 | LL | impl<R: Duh, F: FnMut() -> R> Trait for F { diff --git a/src/test/ui/impl-trait/nested-return-type2.rs b/src/test/ui/impl-trait/nested-return-type2.rs index 39928d543e15d..279641a46c3d0 100644 --- a/src/test/ui/impl-trait/nested-return-type2.rs +++ b/src/test/ui/impl-trait/nested-return-type2.rs @@ -1,5 +1,3 @@ -// check-pass - trait Duh {} impl Duh for i32 {} @@ -20,11 +18,9 @@ impl<R: Duh, F: FnMut() -> R> Trait for F { // the hidden type. We already have obligations registered on the inference // var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque // type does not implement `Duh`, even if its hidden type does. -// 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> { + //~^ ERROR `impl Send: Duh` is not satisfied || 42 } -fn main() { -} +fn main() {} diff --git a/src/test/ui/impl-trait/nested-return-type2.stderr b/src/test/ui/impl-trait/nested-return-type2.stderr new file mode 100644 index 0000000000000..f28a084af89a4 --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type2.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `impl Send: Duh` is not satisfied + --> $DIR/nested-return-type2.rs:21:13 + | +LL | fn foo() -> impl Trait<Assoc = impl Send> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `impl Send` + | + = help: the trait `Duh` is implemented for `i32` +note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2.rs:23:5: 23:7]` + --> $DIR/nested-return-type2.rs:12:31 + | +LL | impl<R: Duh, F: FnMut() -> R> Trait for F { + | ^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index c8ebed3bfd9ae..3d4ae11e57670 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -94,7 +94,7 @@ error[E0599]: no method named `method` found for struct `Foo` in the current sco --> $DIR/no-method-suggested-traits.rs:40:9 | LL | struct Foo; - | ----------- method `method` not found for this + | ---------- method `method` not found for this struct ... LL | Foo.method(); | ^^^^^^ method not found in `Foo` @@ -201,7 +201,7 @@ error[E0599]: no method named `method3` found for struct `Foo` in the current sc --> $DIR/no-method-suggested-traits.rs:59:9 | LL | struct Foo; - | ----------- method `method3` not found for this + | ---------- method `method3` not found for this struct ... LL | Foo.method3(); | ^^^^^^^ method not found in `Foo` @@ -224,7 +224,7 @@ error[E0599]: no method named `method3` found for enum `Bar` in the current scop --> $DIR/no-method-suggested-traits.rs:63:12 | LL | enum Bar { X } - | -------- method `method3` not found for this + | -------- method `method3` not found for this enum ... LL | Bar::X.method3(); | ^^^^^^^ method not found in `Bar` diff --git a/src/test/ui/impl-trait/printing-binder.rs b/src/test/ui/impl-trait/printing-binder.rs new file mode 100644 index 0000000000000..273b5dcdb0985 --- /dev/null +++ b/src/test/ui/impl-trait/printing-binder.rs @@ -0,0 +1,14 @@ +trait Trait<'a> {} +impl<T> Trait<'_> for T {} +fn whatever() -> impl for<'a> Trait<'a> + for<'b> Trait<'b> {} + +fn whatever2() -> impl for<'c> Fn(&'c ()) { + |_: &()| {} +} + +fn main() { + let x: u32 = whatever(); + //~^ ERROR mismatched types + let x2: u32 = whatever2(); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/impl-trait/printing-binder.stderr b/src/test/ui/impl-trait/printing-binder.stderr new file mode 100644 index 0000000000000..5ffec8af10289 --- /dev/null +++ b/src/test/ui/impl-trait/printing-binder.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/printing-binder.rs:10:18 + | +LL | fn whatever() -> impl for<'a> Trait<'a> + for<'b> Trait<'b> {} + | ------------------------------------------ the found opaque type +... +LL | let x: u32 = whatever(); + | --- ^^^^^^^^^^ expected `u32`, found opaque type + | | + | expected due to this + | + = note: expected type `u32` + found opaque type `impl for<'a> Trait<'a> + for<'b> Trait<'b>` + +error[E0308]: mismatched types + --> $DIR/printing-binder.rs:12:19 + | +LL | fn whatever2() -> impl for<'c> Fn(&'c ()) { + | ----------------------- the found opaque type +... +LL | let x2: u32 = whatever2(); + | --- ^^^^^^^^^^^ expected `u32`, found opaque type + | | + | expected due to this + | + = note: expected type `u32` + found opaque type `impl for<'c> Fn(&'c ())` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index b9b2ce249f7bf..2e34d3d4275ad 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -54,7 +54,7 @@ LL | fn closure_capture() -> impl Sized { LL | / move || { LL | | x; LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 @@ -65,7 +65,7 @@ LL | fn closure_ref_capture() -> impl Sized { LL | / move || { LL | | &x; LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 @@ -74,7 +74,7 @@ LL | fn closure_sig() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | || closure_sig() - | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]` + | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 @@ -83,7 +83,7 @@ LL | fn generator_sig() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | || generator_sig() - | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]` + | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 @@ -95,7 +95,7 @@ LL | / move || { LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 @@ -117,7 +117,7 @@ LL | | let x = generator_hold(); LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 74:12]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index bc8e39f9c504c..951abb127c13f 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,7 +2,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/static-return-lifetime-infered.rs:7:9 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { - | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here + | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -15,7 +15,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/static-return-lifetime-infered.rs:7:9 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { - | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here + | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -28,7 +28,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/static-return-lifetime-infered.rs:12:9 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { - | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here + | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -41,7 +41,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/static-return-lifetime-infered.rs:12:9 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { - | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here + | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/imports/inaccessible_type_aliases.rs b/src/test/ui/imports/inaccessible_type_aliases.rs new file mode 100644 index 0000000000000..c3d4214e282d7 --- /dev/null +++ b/src/test/ui/imports/inaccessible_type_aliases.rs @@ -0,0 +1,14 @@ +mod a { + type Foo = u64; + type Bar = u64; +} + +mod b { + type Foo = u64; +} + +fn main() { + let x: Foo = 100; //~ ERROR: cannot find type `Foo` in this scope + let y: Bar = 100; //~ ERROR: cannot find type `Bar` in this scope + println!("x: {}, y: {}", x, y); +} diff --git a/src/test/ui/imports/inaccessible_type_aliases.stderr b/src/test/ui/imports/inaccessible_type_aliases.stderr new file mode 100644 index 0000000000000..ef224246061d9 --- /dev/null +++ b/src/test/ui/imports/inaccessible_type_aliases.stderr @@ -0,0 +1,30 @@ +error[E0412]: cannot find type `Foo` in this scope + --> $DIR/inaccessible_type_aliases.rs:11:12 + | +LL | let x: Foo = 100; + | ^^^ not found in this scope + | +note: these type aliases exist but are inaccessible + --> $DIR/inaccessible_type_aliases.rs:2:5 + | +LL | type Foo = u64; + | ^^^^^^^^^^^^^^^ `a::Foo`: not accessible +... +LL | type Foo = u64; + | ^^^^^^^^^^^^^^^ `b::Foo`: not accessible + +error[E0412]: cannot find type `Bar` in this scope + --> $DIR/inaccessible_type_aliases.rs:12:12 + | +LL | let y: Bar = 100; + | ^^^ not found in this scope + | +note: type alias `a::Bar` exists but is inaccessible + --> $DIR/inaccessible_type_aliases.rs:3:5 + | +LL | type Bar = u64; + | ^^^^^^^^^^^^^^^ not accessible + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/imports/unused-imports-in-test-mode.rs b/src/test/ui/imports/unused-imports-in-test-mode.rs index ed0bb65b3aa91..039f59a8838a1 100644 --- a/src/test/ui/imports/unused-imports-in-test-mode.rs +++ b/src/test/ui/imports/unused-imports-in-test-mode.rs @@ -8,76 +8,94 @@ fn a() {} fn b() {} mod test { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod tests { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod test_a { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod a_test { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod tests_a { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod a_tests { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod fastest_search { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } #[cfg(test)] mod test_has_attr { - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } mod test_has_no_attr { #[cfg(test)] - use super::a; //~ ERROR unused import: `super::a` + use super::a; + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; //~ ERROR unused import: `crate::b` } } diff --git a/src/test/ui/imports/unused-imports-in-test-mode.stderr b/src/test/ui/imports/unused-imports-in-test-mode.stderr index 1847abd64b4f2..c5faaa11450cb 100644 --- a/src/test/ui/imports/unused-imports-in-test-mode.stderr +++ b/src/test/ui/imports/unused-imports-in-test-mode.stderr @@ -10,113 +10,59 @@ note: the lint level is defined here LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:11:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:14:13 + --> $DIR/unused-imports-in-test-mode.rs:16:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:19:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:22:13 + --> $DIR/unused-imports-in-test-mode.rs:26:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:27:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:30:13 + --> $DIR/unused-imports-in-test-mode.rs:36:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:35:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:38:13 + --> $DIR/unused-imports-in-test-mode.rs:46:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:43:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:46:13 + --> $DIR/unused-imports-in-test-mode.rs:56:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:51:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:54:13 + --> $DIR/unused-imports-in-test-mode.rs:66:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:59:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:62:13 + --> $DIR/unused-imports-in-test-mode.rs:76:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:68:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:71:13 + --> $DIR/unused-imports-in-test-mode.rs:87:13 | LL | use crate::b; | ^^^^^^^^ -error: unused import: `super::a` - --> $DIR/unused-imports-in-test-mode.rs:77:9 - | -LL | use super::a; - | ^^^^^^^^ - error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-mode.rs:80:13 + --> $DIR/unused-imports-in-test-mode.rs:98:13 | LL | use crate::b; | ^^^^^^^^ -error: aborting due to 19 previous errors +error: aborting due to 10 previous errors diff --git a/src/test/ui/imports/unused-imports-in-test-module.rs b/src/test/ui/imports/unused-imports-in-test-module.rs index b003b99b6cff0..7849c3fcd4835 100644 --- a/src/test/ui/imports/unused-imports-in-test-module.rs +++ b/src/test/ui/imports/unused-imports-in-test-module.rs @@ -6,58 +6,83 @@ fn a() {} fn b() {} mod test { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; } } mod tests { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; } } mod test_a { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; } } mod a_test { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; } } mod tests_a { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; } } mod a_tests { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; } } mod fastest_search { - use super::a; //~ ERROR unused import: `super::a` + use super::a; //~ ERROR unused import: `super::a` + #[test] fn foo() { - use crate::b; //~ ERROR unused import: `crate::b` + a(); + use crate::b; + } +} + +#[cfg(test)] +mod test_has_attr { + use super::a; + + #[test] + fn foo() { + a(); + use crate::b; } } diff --git a/src/test/ui/imports/unused-imports-in-test-module.stderr b/src/test/ui/imports/unused-imports-in-test-module.stderr index 2efea5b3609e1..1598368eb32cc 100644 --- a/src/test/ui/imports/unused-imports-in-test-module.stderr +++ b/src/test/ui/imports/unused-imports-in-test-module.stderr @@ -22,149 +22,71 @@ help: consider adding a `#[cfg(test)]` to the containing module LL | mod test { | ^^^^^^^^ -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:12:13 - | -LL | use crate::b; - | ^^^^^^^^ - | -help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:8:1 - | -LL | mod test { - | ^^^^^^^^ - error: unused import: `super::a` - --> $DIR/unused-imports-in-test-module.rs:17:9 + --> $DIR/unused-imports-in-test-module.rs:19:9 | LL | use super::a; | ^^^^^^^^ | help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:16:1 - | -LL | mod tests { - | ^^^^^^^^^ - -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:20:13 - | -LL | use crate::b; - | ^^^^^^^^ - | -help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:16:1 + --> $DIR/unused-imports-in-test-module.rs:18:1 | LL | mod tests { | ^^^^^^^^^ error: unused import: `super::a` - --> $DIR/unused-imports-in-test-module.rs:25:9 + --> $DIR/unused-imports-in-test-module.rs:29:9 | LL | use super::a; | ^^^^^^^^ | help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:24:1 - | -LL | mod test_a { - | ^^^^^^^^^^ - -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:28:13 - | -LL | use crate::b; - | ^^^^^^^^ - | -help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:24:1 + --> $DIR/unused-imports-in-test-module.rs:28:1 | LL | mod test_a { | ^^^^^^^^^^ error: unused import: `super::a` - --> $DIR/unused-imports-in-test-module.rs:33:9 + --> $DIR/unused-imports-in-test-module.rs:39:9 | LL | use super::a; | ^^^^^^^^ | help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:32:1 - | -LL | mod a_test { - | ^^^^^^^^^^ - -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:36:13 - | -LL | use crate::b; - | ^^^^^^^^ - | -help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:32:1 + --> $DIR/unused-imports-in-test-module.rs:38:1 | LL | mod a_test { | ^^^^^^^^^^ error: unused import: `super::a` - --> $DIR/unused-imports-in-test-module.rs:41:9 + --> $DIR/unused-imports-in-test-module.rs:49:9 | LL | use super::a; | ^^^^^^^^ | help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:40:1 - | -LL | mod tests_a { - | ^^^^^^^^^^^ - -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:44:13 - | -LL | use crate::b; - | ^^^^^^^^ - | -help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:40:1 + --> $DIR/unused-imports-in-test-module.rs:48:1 | LL | mod tests_a { | ^^^^^^^^^^^ error: unused import: `super::a` - --> $DIR/unused-imports-in-test-module.rs:49:9 + --> $DIR/unused-imports-in-test-module.rs:59:9 | LL | use super::a; | ^^^^^^^^ | help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:48:1 - | -LL | mod a_tests { - | ^^^^^^^^^^^ - -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:52:13 - | -LL | use crate::b; - | ^^^^^^^^ - | -help: consider adding a `#[cfg(test)]` to the containing module - --> $DIR/unused-imports-in-test-module.rs:48:1 + --> $DIR/unused-imports-in-test-module.rs:58:1 | LL | mod a_tests { | ^^^^^^^^^^^ error: unused import: `super::a` - --> $DIR/unused-imports-in-test-module.rs:57:9 + --> $DIR/unused-imports-in-test-module.rs:69:9 | LL | use super::a; | ^^^^^^^^ -error: unused import: `crate::b` - --> $DIR/unused-imports-in-test-module.rs:60:13 - | -LL | use crate::b; - | ^^^^^^^^ - -error: aborting due to 15 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/ui/inference/ambiguous_type_parameter.stderr b/src/test/ui/inference/ambiguous_type_parameter.stderr index a08342371b3b5..9cbe221de1393 100644 --- a/src/test/ui/inference/ambiguous_type_parameter.stderr +++ b/src/test/ui/inference/ambiguous_type_parameter.stderr @@ -2,7 +2,12 @@ error[E0282]: type annotations needed --> $DIR/ambiguous_type_parameter.rs:16:19 | LL | InMemoryStore.get_raw(&String::default()); - | ^^^^^^^ cannot infer type for type parameter `K` + | ^^^^^^^ + | +help: try using a fully qualified path to specify the expected types + | +LL | <InMemoryStore as Store<String, HashMap<K, String>>>::get_raw(&InMemoryStore, &String::default()); + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ~ error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs index 976827a447860..b555697dc3461 100644 --- a/src/test/ui/inference/cannot-infer-partial-try-return.rs +++ b/src/test/ui/inference/cannot-infer-partial-try-return.rs @@ -16,8 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> { fn main() { let x = || -> Result<_, QualifiedError<_>> { - //~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>` infallible()?; Ok(()) + //~^ ERROR type annotations needed }; } diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr index 220602c124cb1..2a56aaa44fef2 100644 --- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr +++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr @@ -1,13 +1,15 @@ -error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>` - --> $DIR/cannot-infer-partial-try-return.rs:18:13 +error[E0282]: type annotations needed + --> $DIR/cannot-infer-partial-try-return.rs:20:9 | -LL | let x = || -> Result<_, QualifiedError<_>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | infallible()?; + | ------------- type must be known at this point +LL | Ok(()) + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` | -help: try giving this closure an explicit return type +help: consider specifying the generic arguments | -LL | let x = || -> Result<(), QualifiedError<_>> { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | Ok::<(), QualifiedError<_>>(()) + | +++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/inference/erase-type-params-in-label.stderr b/src/test/ui/inference/erase-type-params-in-label.stderr index fd58844c2380a..5c52e7bcfab69 100644 --- a/src/test/ui/inference/erase-type-params-in-label.stderr +++ b/src/test/ui/inference/erase-type-params-in-label.stderr @@ -2,7 +2,7 @@ error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>` --> $DIR/erase-type-params-in-label.rs:2:9 | LL | let foo = foo(1, ""); - | ^^^ + | ^^^ --- type must be known at this point | = note: cannot satisfy `_: Default` note: required by a bound in `foo` @@ -10,10 +10,6 @@ note: required by a bound in `foo` | LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> { | ^^^^^^^ required by this bound in `foo` -help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified - | -LL | let foo: Foo<i32, &str, W, Z> = foo(1, ""); - | ++++++++++++++++++++++ help: consider specifying the type arguments in the function call | LL | let foo = foo::<T, K, W, Z>(1, ""); @@ -23,7 +19,7 @@ error[E0283]: type annotations needed for `Bar<i32, &str, Z>` --> $DIR/erase-type-params-in-label.rs:5:9 | LL | let bar = bar(1, ""); - | ^^^ + | ^^^ --- type must be known at this point | = note: cannot satisfy `_: Default` note: required by a bound in `bar` @@ -31,10 +27,6 @@ note: required by a bound in `bar` | LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> { | ^^^^^^^ required by this bound in `bar` -help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified - | -LL | let bar: Bar<i32, &str, Z> = bar(1, ""); - | +++++++++++++++++++ help: consider specifying the type arguments in the function call | LL | let bar = bar::<T, K, Z>(1, ""); diff --git a/src/test/ui/inference/issue-71732.stderr b/src/test/ui/inference/issue-71732.stderr index db153d38aaa9f..04673a375cf01 100644 --- a/src/test/ui/inference/issue-71732.stderr +++ b/src/test/ui/inference/issue-71732.stderr @@ -13,10 +13,6 @@ note: required by a bound in `HashMap::<K, V, S>::get` | LL | K: Borrow<Q>, | ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get` -help: consider specifying the generic argument - | -LL | .get::<Q>(&"key".into()) - | +++++ help: consider specifying the type argument in the function call | LL | .get::<Q>(&"key".into()) diff --git a/src/test/ui/inference/issue-72616.stderr b/src/test/ui/inference/issue-72616.stderr index 3c53d8126e778..a71ce9a8ef27a 100644 --- a/src/test/ui/inference/issue-72616.stderr +++ b/src/test/ui/inference/issue-72616.stderr @@ -2,7 +2,9 @@ error[E0283]: type annotations needed --> $DIR/issue-72616.rs:20:37 | LL | if String::from("a") == "a".try_into().unwrap() {} - | ^^^^^^^^ + | -- ^^^^^^^^ + | | + | type must be known at this point | = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate: - impl PartialEq for String; diff --git a/src/test/ui/inference/issue-72690.stderr b/src/test/ui/inference/issue-72690.stderr index 9edf14ef291f9..d4eeda07366a8 100644 --- a/src/test/ui/inference/issue-72690.stderr +++ b/src/test/ui/inference/issue-72690.stderr @@ -55,7 +55,7 @@ error[E0283]: type annotations needed for `&T` --> $DIR/issue-72690.rs:17:9 | LL | let _ = "x".as_ref(); - | ^ + | ^ ------ type must be known at this point | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: - impl AsRef<OsStr> for str; diff --git a/src/test/ui/inference/issue-86162-1.stderr b/src/test/ui/inference/issue-86162-1.stderr index 6641b29b30b0b..e395e65fad066 100644 --- a/src/test/ui/inference/issue-86162-1.stderr +++ b/src/test/ui/inference/issue-86162-1.stderr @@ -2,7 +2,9 @@ error[E0283]: type annotations needed --> $DIR/issue-86162-1.rs:7:9 | LL | foo(gen()); //<- Do not suggest `foo::<impl Clone>()`! - | ^^^ cannot infer type of the type parameter `T` declared on the function `gen` + | --- ^^^ cannot infer type of the type parameter `T` declared on the function `gen` + | | + | type must be known at this point | = note: cannot satisfy `_: Clone` note: required by a bound in `foo` diff --git a/src/test/ui/inference/issue-86162-2.stderr b/src/test/ui/inference/issue-86162-2.stderr index d2a026a9269c6..30e6e10eaa2fd 100644 --- a/src/test/ui/inference/issue-86162-2.stderr +++ b/src/test/ui/inference/issue-86162-2.stderr @@ -2,7 +2,9 @@ error[E0283]: type annotations needed --> $DIR/issue-86162-2.rs:12:14 | LL | Foo::bar(gen()); //<- Do not suggest `Foo::bar::<impl Clone>()`! - | ^^^ cannot infer type of the type parameter `T` declared on the function `gen` + | -------- ^^^ cannot infer type of the type parameter `T` declared on the function `gen` + | | + | type must be known at this point | = note: cannot satisfy `_: Clone` note: required by a bound in `Foo::bar` diff --git a/src/test/ui/inference/need_type_info/channel.rs b/src/test/ui/inference/need_type_info/channel.rs new file mode 100644 index 0000000000000..e2ba5a9417138 --- /dev/null +++ b/src/test/ui/inference/need_type_info/channel.rs @@ -0,0 +1,19 @@ +// Test that we suggest specifying the generic argument of `channel` +// instead of the return type of that function, which is a lot more +// complex. +use std::sync::mpsc::channel; + +fn no_tuple() { + let _data = + channel(); //~ ERROR type annotations needed +} + +fn tuple() { + let (_sender, _receiver) = + channel(); //~ ERROR type annotations needed +} + +fn main() { + no_tuple(); + tuple(); +} diff --git a/src/test/ui/inference/need_type_info/channel.stderr b/src/test/ui/inference/need_type_info/channel.stderr new file mode 100644 index 0000000000000..e33ace0338d50 --- /dev/null +++ b/src/test/ui/inference/need_type_info/channel.stderr @@ -0,0 +1,25 @@ +error[E0282]: type annotations needed + --> $DIR/channel.rs:8:9 + | +LL | channel(); + | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel` + | +help: consider specifying the generic argument + | +LL | channel::<T>(); + | +++++ + +error[E0282]: type annotations needed + --> $DIR/channel.rs:13:9 + | +LL | channel(); + | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel` + | +help: consider specifying the generic argument + | +LL | channel::<T>(); + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative-enum.rs b/src/test/ui/inference/need_type_info/expr-struct-type-relative-enum.rs new file mode 100644 index 0000000000000..42af9fa8d113a --- /dev/null +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative-enum.rs @@ -0,0 +1,21 @@ +trait Foo { + type Output; + + fn baz() -> Self::Output; +} + +fn needs_infer<T>() {} + +enum Bar { + Variant {} +} + +impl Foo for u8 { + type Output = Bar; + fn baz() -> Self::Output { + needs_infer(); //~ ERROR type annotations needed + Self::Output::Variant {} + } +} + +fn main() {} diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative-enum.stderr b/src/test/ui/inference/need_type_info/expr-struct-type-relative-enum.stderr new file mode 100644 index 0000000000000..68ecb38134837 --- /dev/null +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative-enum.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/expr-struct-type-relative-enum.rs:16:9 + | +LL | needs_infer(); + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `needs_infer` + | +help: consider specifying the generic argument + | +LL | needs_infer::<T>(); + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs new file mode 100644 index 0000000000000..bcd29bb4e3495 --- /dev/null +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs @@ -0,0 +1,21 @@ +#![feature(generic_associated_types)] + +trait Foo { + type Output<T>; + + fn baz(); +} + +enum Bar<T> { + Simple {}, + Generic(T), +} + +impl Foo for u8 { + type Output<T> = Bar<T>; + fn baz() { + Self::Output::Simple {}; //~ ERROR type annotations needed + } +} + +fn main() {} diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr new file mode 100644 index 0000000000000..65a75b68c1f08 --- /dev/null +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/expr-struct-type-relative-gat.rs:17:9 + | +LL | Self::Output::Simple {}; + | ^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated type `Output` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative.rs b/src/test/ui/inference/need_type_info/expr-struct-type-relative.rs new file mode 100644 index 0000000000000..c3ece2b16cf08 --- /dev/null +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative.rs @@ -0,0 +1,21 @@ +// regression test for #98598 + +trait Foo { + type Output; + + fn baz() -> Self::Output; +} + +fn needs_infer<T>() {} + +struct Bar {} + +impl Foo for u8 { + type Output = Bar; + fn baz() -> Self::Output { + needs_infer(); //~ ERROR type annotations needed + Self::Output {} + } +} + +fn main() {} diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative.stderr b/src/test/ui/inference/need_type_info/expr-struct-type-relative.stderr new file mode 100644 index 0000000000000..397d8e7be04ff --- /dev/null +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/expr-struct-type-relative.rs:16:9 + | +LL | needs_infer(); + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `needs_infer` + | +help: consider specifying the generic argument + | +LL | needs_infer::<T>(); + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index 2e950dbb8c7f9..51b61e3a66bb4 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -43,7 +43,7 @@ error[E0599]: no method named `bar` found for struct `Foo` in the current scope --> $DIR/infinite-autoderef.rs:25:9 | LL | struct Foo; - | ----------- method `bar` not found for this + | ---------- method `bar` not found for this struct ... LL | Foo.bar(); | ^^^ method not found in `Foo` diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs index 70a203ea6e814..74185dc597b52 100644 --- a/src/test/ui/infinite/infinite-struct.rs +++ b/src/test/ui/infinite/infinite-struct.rs @@ -1,6 +1,5 @@ struct Take(Take); //~^ ERROR has infinite size -//~| ERROR cycle detected // check that we don't hang trying to find the tail of a recursive struct (#79437) fn foo() -> Take { diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr index 383e13fd4b09d..5a6d13786d197 100644 --- a/src/test/ui/infinite/infinite-struct.stderr +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -2,9 +2,8 @@ error[E0072]: recursive type `Take` has infinite size --> $DIR/infinite-struct.rs:1:1 | LL | struct Take(Take); - | ^^^^^^^^^^^^----^^ - | | | - | | recursive without indirection + | ^^^^^^^^^^^ ---- recursive without indirection + | | | recursive type has infinite size | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` representable @@ -12,16 +11,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` repre LL | struct Take(Box<Take>); | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `Take` - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `Take` again - = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Take } }` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.rs b/src/test/ui/infinite/infinite-tag-type-recursion.rs index 8578c5545bc90..87a9e08dd381a 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.rs +++ b/src/test/ui/infinite/infinite-tag-type-recursion.rs @@ -1,5 +1,4 @@ enum MList { Cons(isize, MList), Nil } //~^ ERROR recursive type `MList` has infinite size -//~| ERROR cycle detected when computing drop-check constraints for `MList` fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); } diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 1802c7599a3b5..d2dad4b9178d9 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -11,16 +11,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `MList` repr LL | enum MList { Cons(isize, Box<MList>), Nil } | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `MList` - --> $DIR/infinite-tag-type-recursion.rs:1:1 - | -LL | enum MList { Cons(isize, MList), Nil } - | ^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `MList` again - = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: MList } }` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/infinite/infinite-trait-alias-recursion.stderr b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr index 5ecaedb3cb2cd..b925b3b018c0a 100644 --- a/src/test/ui/infinite/infinite-trait-alias-recursion.stderr +++ b/src/test/ui/infinite/infinite-trait-alias-recursion.stderr @@ -2,7 +2,7 @@ error[E0391]: cycle detected when computing the super predicates of `T1` --> $DIR/infinite-trait-alias-recursion.rs:3:1 | LL | trait T1 = T2; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ | note: ...which requires computing the super traits of `T1`... --> $DIR/infinite-trait-alias-recursion.rs:3:12 @@ -13,7 +13,7 @@ note: ...which requires computing the super predicates of `T2`... --> $DIR/infinite-trait-alias-recursion.rs:6:1 | LL | trait T2 = T3; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ note: ...which requires computing the super traits of `T2`... --> $DIR/infinite-trait-alias-recursion.rs:6:12 | @@ -23,7 +23,7 @@ note: ...which requires computing the super predicates of `T3`... --> $DIR/infinite-trait-alias-recursion.rs:8:1 | LL | trait T3 = T1 + T3; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ note: ...which requires computing the super traits of `T3`... --> $DIR/infinite-trait-alias-recursion.rs:8:12 | diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index 66fe3c74e2c87..349fb6dafa365 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -11,7 +11,7 @@ note: required because it's used within this closure --> $DIR/interior-mutability.rs:5:18 | LL | catch_unwind(|| { x.set(23); }); - | ^^^^^^^^^^^^^^^^^ + | ^^ note: required by a bound in `catch_unwind` --> $SRC_DIR/std/src/panic.rs:LL:COL | diff --git a/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs b/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs index f65f359875bfd..f3b9d569ce3b1 100644 --- a/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs +++ b/src/test/ui/intrinsics/auxiliary/cci_intrinsic.rs @@ -2,13 +2,13 @@ pub mod rusti { extern "rust-intrinsic" { - pub fn atomic_xchg<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T; } } #[inline(always)] -pub fn atomic_xchg(dst: *mut isize, src: isize) -> isize { +pub fn atomic_xchg_seqcst(dst: *mut isize, src: isize) -> isize { unsafe { - rusti::atomic_xchg(dst, src) + rusti::atomic_xchg_seqcst(dst, src) } } diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs index 7d924e2b7f366..52f4e594f1a0a 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.rs +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -1,4 +1,5 @@ #![feature(const_eval_select)] +#![feature(core_intrinsics)] use std::intrinsics::const_eval_select; diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 79f6a5850b5ef..6103d6c6e3a6f 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -1,18 +1,18 @@ -error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]: ~const FnOnce<()>` is not satisfied - --> $DIR/const-eval-select-bad.rs:6:27 +error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: ~const FnOnce<()>` is not satisfied + --> $DIR/const-eval-select-bad.rs:7:27 | LL | const_eval_select((), || {}, || {}); - | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` + | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` | | | required by a bound introduced by this call | - = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` -note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`, but that implementation is not `const` - --> $DIR/const-eval-select-bad.rs:6:27 + = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` +note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const` + --> $DIR/const-eval-select-bad.rs:7:27 | LL | const_eval_select((), || {}, || {}); | ^^^^^ - = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }` + = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | @@ -20,7 +20,7 @@ LL | F: ~const FnOnce<ARG, Output = RET>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied - --> $DIR/const-eval-select-bad.rs:8:27 + --> $DIR/const-eval-select-bad.rs:9:27 | LL | const_eval_select((), 42, 0xDEADBEEF); | ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}` @@ -36,7 +36,7 @@ LL | F: ~const FnOnce<ARG, Output = RET>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` - --> $DIR/const-eval-select-bad.rs:8:31 + --> $DIR/const-eval-select-bad.rs:9:31 | LL | const_eval_select((), 42, 0xDEADBEEF); | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}` @@ -52,7 +52,7 @@ LL | G: FnOnce<ARG, Output = RET> + ~const Destruct, | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32` - --> $DIR/const-eval-select-bad.rs:28:5 + --> $DIR/const-eval-select-bad.rs:29:5 | LL | const_eval_select((1,), foo, bar); | ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool` @@ -64,7 +64,7 @@ LL | G: FnOnce<ARG, Output = RET> + ~const Destruct, | ^^^^^^^^^^^^ required by this bound in `const_eval_select` error[E0631]: type mismatch in function arguments - --> $DIR/const-eval-select-bad.rs:33:32 + --> $DIR/const-eval-select-bad.rs:34:32 | LL | const fn foo(n: i32) -> i32 { | --------------------------- found signature of `fn(i32) -> _` diff --git a/src/test/ui/intrinsics/const-eval-select-stability.rs b/src/test/ui/intrinsics/const-eval-select-stability.rs index db2462aee5922..f9554decec16b 100644 --- a/src/test/ui/intrinsics/const-eval-select-stability.rs +++ b/src/test/ui/intrinsics/const-eval-select-stability.rs @@ -1,5 +1,6 @@ #![feature(staged_api)] #![feature(const_eval_select)] +#![feature(core_intrinsics)] #![stable(since = "1.0", feature = "ui_test")] use std::intrinsics::const_eval_select; diff --git a/src/test/ui/intrinsics/const-eval-select-stability.stderr b/src/test/ui/intrinsics/const-eval-select-stability.stderr index 79641bbb46abe..65b507b887b46 100644 --- a/src/test/ui/intrinsics/const-eval-select-stability.stderr +++ b/src/test/ui/intrinsics/const-eval-select-stability.stderr @@ -1,5 +1,5 @@ error: `const_eval_select` is not yet stable as a const fn - --> $DIR/const-eval-select-stability.rs:16:5 + --> $DIR/const-eval-select-stability.rs:17:5 | LL | const_eval_select((), nothing, log); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/intrinsics/const-eval-select-x86_64.rs b/src/test/ui/intrinsics/const-eval-select-x86_64.rs index afec8e054bb76..f3924acf0fa8b 100644 --- a/src/test/ui/intrinsics/const-eval-select-x86_64.rs +++ b/src/test/ui/intrinsics/const-eval-select-x86_64.rs @@ -2,6 +2,7 @@ // only-x86_64 #![feature(const_eval_select)] +#![feature(core_intrinsics)] use std::intrinsics::const_eval_select; use std::arch::x86_64::*; use std::mem::transmute; diff --git a/src/test/ui/intrinsics/const-eval-select.rs b/src/test/ui/intrinsics/const-eval-select.rs index 744db2f15b056..9ff20d3fbdd9e 100644 --- a/src/test/ui/intrinsics/const-eval-select.rs +++ b/src/test/ui/intrinsics/const-eval-select.rs @@ -1,6 +1,7 @@ // run-pass #![feature(const_eval_select)] +#![feature(core_intrinsics)] use std::intrinsics::const_eval_select; diff --git a/src/test/ui/intrinsics/intrinsic-atomics-cc.rs b/src/test/ui/intrinsics/intrinsic-atomics-cc.rs index 52e891da9ba77..ce3fa7b0c05e6 100644 --- a/src/test/ui/intrinsics/intrinsic-atomics-cc.rs +++ b/src/test/ui/intrinsics/intrinsic-atomics-cc.rs @@ -3,10 +3,10 @@ extern crate cci_intrinsic; -use cci_intrinsic::atomic_xchg; +use cci_intrinsic::atomic_xchg_seqcst; pub fn main() { let mut x = 1; - atomic_xchg(&mut x, 5); + atomic_xchg_seqcst(&mut x, 5); assert_eq!(x, 5); } diff --git a/src/test/ui/intrinsics/intrinsic-atomics.rs b/src/test/ui/intrinsics/intrinsic-atomics.rs index c6e48e8b5afba..b17f4347be31c 100644 --- a/src/test/ui/intrinsics/intrinsic-atomics.rs +++ b/src/test/ui/intrinsics/intrinsic-atomics.rs @@ -3,31 +3,31 @@ mod rusti { extern "rust-intrinsic" { - pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchg_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_cxchgweak_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool); + pub fn atomic_cxchgweak_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); - pub fn atomic_load<T>(src: *const T) -> T; - pub fn atomic_load_acq<T>(src: *const T) -> T; + pub fn atomic_load_seqcst<T>(src: *const T) -> T; + pub fn atomic_load_acquire<T>(src: *const T) -> T; - pub fn atomic_store<T>(dst: *mut T, val: T); - pub fn atomic_store_rel<T>(dst: *mut T, val: T); + pub fn atomic_store_seqcst<T>(dst: *mut T, val: T); + pub fn atomic_store_release<T>(dst: *mut T, val: T); - pub fn atomic_xchg<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_acq<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xchg_rel<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_acquire<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xchg_release<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_acq<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xadd_rel<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_acquire<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xadd_release<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_acq<T>(dst: *mut T, src: T) -> T; - pub fn atomic_xsub_rel<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_seqcst<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_acquire<T>(dst: *mut T, src: T) -> T; + pub fn atomic_xsub_release<T>(dst: *mut T, src: T) -> T; } } @@ -35,45 +35,45 @@ pub fn main() { unsafe { let mut x: Box<_> = Box::new(1); - assert_eq!(rusti::atomic_load(&*x), 1); + assert_eq!(rusti::atomic_load_seqcst(&*x), 1); *x = 5; - assert_eq!(rusti::atomic_load_acq(&*x), 5); + assert_eq!(rusti::atomic_load_acquire(&*x), 5); - rusti::atomic_store(&mut *x,3); + rusti::atomic_store_seqcst(&mut *x,3); assert_eq!(*x, 3); - rusti::atomic_store_rel(&mut *x,1); + rusti::atomic_store_release(&mut *x,1); assert_eq!(*x, 1); - assert_eq!(rusti::atomic_cxchg(&mut *x, 1, 2), (1, true)); + assert_eq!(rusti::atomic_cxchg_seqcst_seqcst(&mut *x, 1, 2), (1, true)); assert_eq!(*x, 2); - assert_eq!(rusti::atomic_cxchg_acq(&mut *x, 1, 3), (2, false)); + assert_eq!(rusti::atomic_cxchg_acquire_acquire(&mut *x, 1, 3), (2, false)); assert_eq!(*x, 2); - assert_eq!(rusti::atomic_cxchg_rel(&mut *x, 2, 1), (2, true)); + assert_eq!(rusti::atomic_cxchg_release_relaxed(&mut *x, 2, 1), (2, true)); assert_eq!(*x, 1); - assert_eq!(rusti::atomic_xchg(&mut *x, 0), 1); + assert_eq!(rusti::atomic_xchg_seqcst(&mut *x, 0), 1); assert_eq!(*x, 0); - assert_eq!(rusti::atomic_xchg_acq(&mut *x, 1), 0); + assert_eq!(rusti::atomic_xchg_acquire(&mut *x, 1), 0); assert_eq!(*x, 1); - assert_eq!(rusti::atomic_xchg_rel(&mut *x, 0), 1); + assert_eq!(rusti::atomic_xchg_release(&mut *x, 0), 1); assert_eq!(*x, 0); - assert_eq!(rusti::atomic_xadd(&mut *x, 1), 0); - assert_eq!(rusti::atomic_xadd_acq(&mut *x, 1), 1); - assert_eq!(rusti::atomic_xadd_rel(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xadd_seqcst(&mut *x, 1), 0); + assert_eq!(rusti::atomic_xadd_acquire(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xadd_release(&mut *x, 1), 2); assert_eq!(*x, 3); - assert_eq!(rusti::atomic_xsub(&mut *x, 1), 3); - assert_eq!(rusti::atomic_xsub_acq(&mut *x, 1), 2); - assert_eq!(rusti::atomic_xsub_rel(&mut *x, 1), 1); + assert_eq!(rusti::atomic_xsub_seqcst(&mut *x, 1), 3); + assert_eq!(rusti::atomic_xsub_acquire(&mut *x, 1), 2); + assert_eq!(rusti::atomic_xsub_release(&mut *x, 1), 1); assert_eq!(*x, 0); loop { - let res = rusti::atomic_cxchgweak(&mut *x, 0, 1); + let res = rusti::atomic_cxchgweak_seqcst_seqcst(&mut *x, 0, 1); assert_eq!(res.0, 0); if res.1 { break; @@ -82,7 +82,7 @@ pub fn main() { assert_eq!(*x, 1); loop { - let res = rusti::atomic_cxchgweak_acq(&mut *x, 1, 2); + let res = rusti::atomic_cxchgweak_acquire_acquire(&mut *x, 1, 2); assert_eq!(res.0, 1); if res.1 { break; @@ -91,7 +91,7 @@ pub fn main() { assert_eq!(*x, 2); loop { - let res = rusti::atomic_cxchgweak_rel(&mut *x, 2, 3); + let res = rusti::atomic_cxchgweak_release_relaxed(&mut *x, 2, 3); assert_eq!(res.0, 2); if res.1 { break; diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr index ff78c252731bd..9322654b2928b 100644 --- a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr +++ b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/intrinsic-raw_eq-const-padding.rs:6:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 4 bytes of memory starting at alloc3, but 1 byte is uninitialized starting at alloc3+0x1, and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory error: aborting due to previous error diff --git a/src/test/ui/intrinsics/non-integer-atomic.rs b/src/test/ui/intrinsics/non-integer-atomic.rs index 00a7f368a0fa8..85ea81ba67961 100644 --- a/src/test/ui/intrinsics/non-integer-atomic.rs +++ b/src/test/ui/intrinsics/non-integer-atomic.rs @@ -12,81 +12,81 @@ pub type Bar = &'static Fn(); pub type Quux = [u8; 100]; pub unsafe fn test_bool_load(p: &mut bool, v: bool) { - intrinsics::atomic_load(p); - //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_load_seqcst(p); + //~^ ERROR `atomic_load_seqcst` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_bool_store(p: &mut bool, v: bool) { - intrinsics::atomic_store(p, v); - //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_bool_xchg(p: &mut bool, v: bool) { - intrinsics::atomic_xchg(p, v); - //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_bool_cxchg(p: &mut bool, v: bool) { - intrinsics::atomic_cxchg(p, v, v); - //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `bool` + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `bool` } pub unsafe fn test_Foo_load(p: &mut Foo, v: Foo) { - intrinsics::atomic_load(p); - //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_load_seqcst(p); + //~^ ERROR `atomic_load_seqcst` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Foo_store(p: &mut Foo, v: Foo) { - intrinsics::atomic_store(p, v); - //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Foo_xchg(p: &mut Foo, v: Foo) { - intrinsics::atomic_xchg(p, v); - //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { - intrinsics::atomic_cxchg(p, v, v); - //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `Foo` } pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { - intrinsics::atomic_load(p); + intrinsics::atomic_load_seqcst(p); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { - intrinsics::atomic_store(p, v); + intrinsics::atomic_store_seqcst(p, v); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { - intrinsics::atomic_xchg(p, v); + intrinsics::atomic_xchg_seqcst(p, v); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { - intrinsics::atomic_cxchg(p, v, v); + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { - intrinsics::atomic_load(p); - //~^ ERROR `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_load_seqcst(p); + //~^ ERROR `atomic_load_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` } pub unsafe fn test_Quux_store(p: &mut Quux, v: Quux) { - intrinsics::atomic_store(p, v); - //~^ ERROR `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_store_seqcst(p, v); + //~^ ERROR `atomic_store_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` } pub unsafe fn test_Quux_xchg(p: &mut Quux, v: Quux) { - intrinsics::atomic_xchg(p, v); - //~^ ERROR `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_xchg_seqcst(p, v); + //~^ ERROR `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` } pub unsafe fn test_Quux_cxchg(p: &mut Quux, v: Quux) { - intrinsics::atomic_cxchg(p, v, v); - //~^ ERROR `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` + intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + //~^ ERROR `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` } diff --git a/src/test/ui/intrinsics/non-integer-atomic.stderr b/src/test/ui/intrinsics/non-integer-atomic.stderr index ee485c21cd696..32791a8e8b7f1 100644 --- a/src/test/ui/intrinsics/non-integer-atomic.stderr +++ b/src/test/ui/intrinsics/non-integer-atomic.stderr @@ -1,98 +1,98 @@ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:15:5 | -LL | intrinsics::atomic_load(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:20:5 | -LL | intrinsics::atomic_store(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:25:5 | -LL | intrinsics::atomic_xchg(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `bool` +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `bool` --> $DIR/non-integer-atomic.rs:30:5 | -LL | intrinsics::atomic_cxchg(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:35:5 | -LL | intrinsics::atomic_load(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:40:5 | -LL | intrinsics::atomic_store(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:45:5 | -LL | intrinsics::atomic_xchg(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `Foo` --> $DIR/non-integer-atomic.rs:50:5 | -LL | intrinsics::atomic_cxchg(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:55:5 | -LL | intrinsics::atomic_load(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:60:5 | -LL | intrinsics::atomic_store(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:65:5 | -LL | intrinsics::atomic_xchg(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn Fn()` +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:70:5 | -LL | intrinsics::atomic_cxchg(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_load_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:75:5 | -LL | intrinsics::atomic_load(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load_seqcst(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_store_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:80:5 | -LL | intrinsics::atomic_store(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_xchg_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:85:5 | -LL | intrinsics::atomic_xchg(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg_seqcst(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` +error[E0511]: invalid monomorphization of `atomic_cxchg_seqcst_seqcst` intrinsic: expected basic integer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:90:5 | -LL | intrinsics::atomic_cxchg(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg_seqcst_seqcst(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 16 previous errors diff --git a/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr index 5528d2a0729c9..d0e8d4719d307 100644 --- a/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr +++ b/src/test/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr @@ -1,2 +1,2 @@ -error: incorrect value `leaf` for debugging option `branch-protection` - a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf` was expected +error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf` was expected diff --git a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr index 6d62d4fd0711d..b5b32d2f0bd36 100644 --- a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr @@ -1,22 +1,16 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1 | -LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T> -LL | | where -LL | | T: DispatchFromDyn<U>, -LL | | {} - | |__^ +LL | impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: extra field `1` of type `i32` is not allowed error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions --> $DIR/invalid_dispatch_from_dyn_impls.rs:21:1 | -LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T> -LL | | where -LL | | T: Unsize<U>, -LL | | {} - | |__^ +LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced = note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`) @@ -25,25 +19,19 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion --> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1 | LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]` --> $DIR/invalid_dispatch_from_dyn_impls.rs:37:1 | -LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T> -LL | | where -LL | | T: Unsize<U>, -LL | | {} - | |__^ +LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1 | -LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T> -LL | | where -LL | | T: Unsize<U>, -LL | | {} - | |__^ +LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: extra field `1` of type `OverAlignedZst` is not allowed diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index 30cb7a1df8071..8d6b81c24b682 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -1,8 +1,14 @@ -error[E0284]: type annotations needed: cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S` +error[E0284]: type annotations needed --> $DIR/issue-12028.rs:27:14 | LL | self.input_stream(&mut stream); - | ^^^^^^^^^^^^ cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S` + | ^^^^^^^^^^^^ + | + = note: cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S` +help: try using a fully qualified path to specify the expected types + | +LL | <u8 as StreamHash<H>>::input_stream(self, &mut stream); + | ++++++++++++++++++++++++++++++++++++ ~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr index e1559ab2feaa7..2c451b07fbe3a 100644 --- a/src/test/ui/issues/issue-12127.stderr +++ b/src/test/ui/issues/issue-12127.stderr @@ -11,7 +11,7 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | f(); | ^ - = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41]`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:30]`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14091-2.stderr b/src/test/ui/issues/issue-14091-2.stderr index fbfa6e1abb2da..a191afd7980c6 100644 --- a/src/test/ui/issues/issue-14091-2.stderr +++ b/src/test/ui/issues/issue-14091-2.stderr @@ -8,18 +8,12 @@ note: an implementation of `Not` might be missing for `BytePos` --> $DIR/issue-14091-2.rs:6:1 | LL | pub struct BytePos(pub u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `Not` + | ^^^^^^^^^^^^^^^^^^ must implement `Not` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait Not { -LL | | /// The resulting type after applying the `!` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn not(self) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Not { + | ^^^^^^^^^^^^^ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index b96b07c91a1fe..10a73b245ac57 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -5,7 +5,7 @@ LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn Any` + = note: required for the cast from `str` to the object type `dyn Any` help: consider borrowing the value, since `&str` can be coerced into `dyn Any` | LL | let _x = &"test" as &dyn (::std::any::Any); diff --git a/src/test/ui/issues/issue-15524.stderr b/src/test/ui/issues/issue-15524.stderr index a0ea0c2459f7c..1195e0a346ddf 100644 --- a/src/test/ui/issues/issue-15524.stderr +++ b/src/test/ui/issues/issue-15524.stderr @@ -1,53 +1,39 @@ error[E0081]: discriminant value `1` assigned more than once --> $DIR/issue-15524.rs:3:1 | -LL | / enum Foo { -LL | | -LL | | -LL | | -LL | | A = 1, - | | - first assignment of `1` -LL | | B = 1, - | | - second assignment of `1` -... | -LL | | -LL | | } - | |_^ +LL | enum Foo { + | ^^^^^^^^ +... +LL | A = 1, + | - first assignment of `1` +LL | B = 1, + | - second assignment of `1` error[E0081]: discriminant value `1` assigned more than once --> $DIR/issue-15524.rs:3:1 | -LL | / enum Foo { -LL | | -LL | | -LL | | -LL | | A = 1, - | | - first assignment of `1` -LL | | B = 1, -LL | | C = 0, - | | ----- assigned discriminant for `D` was incremented from this discriminant -LL | | D, - | | - second assignment of `1` -... | -LL | | -LL | | } - | |_^ +LL | enum Foo { + | ^^^^^^^^ +... +LL | A = 1, + | - first assignment of `1` +LL | B = 1, +LL | C = 0, + | ----- assigned discriminant for `D` was incremented from this discriminant +LL | D, + | - second assignment of `1` error[E0081]: discriminant value `1` assigned more than once --> $DIR/issue-15524.rs:3:1 | -LL | / enum Foo { -LL | | -LL | | -LL | | -LL | | A = 1, - | | - first assignment of `1` -... | -LL | | E = N, - | | - second assignment of `1` -LL | | -LL | | } - | |_^ +LL | enum Foo { + | ^^^^^^^^ +... +LL | A = 1, + | - first assignment of `1` +... +LL | E = N, + | - second assignment of `1` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-15965.stderr b/src/test/ui/issues/issue-15965.stderr index 90377c19dee02..fe06810b8dff4 100644 --- a/src/test/ui/issues/issue-15965.stderr +++ b/src/test/ui/issues/issue-15965.stderr @@ -5,8 +5,6 @@ LL | / { return () } LL | | LL | | () | |______^ cannot infer type - | - = note: type must be known at this point error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16250.stderr b/src/test/ui/issues/issue-16250.stderr index 45f854f93ecb9..ae3b7f334c65a 100644 --- a/src/test/ui/issues/issue-16250.stderr +++ b/src/test/ui/issues/issue-16250.stderr @@ -16,7 +16,7 @@ note: the type is defined here --> $DIR/issue-16250.rs:3:1 | LL | pub struct Foo; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16725.stderr b/src/test/ui/issues/issue-16725.stderr index 84359803bbae7..5f6eae73e5850 100644 --- a/src/test/ui/issues/issue-16725.stderr +++ b/src/test/ui/issues/issue-16725.stderr @@ -8,7 +8,7 @@ note: the function `bar` is defined here --> $DIR/auxiliary/issue-16725.rs:2:5 | LL | fn bar(); - | ^^^^^^^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16939.stderr b/src/test/ui/issues/issue-16939.stderr index 294524f0b6148..aaa3c49b3d83e 100644 --- a/src/test/ui/issues/issue-16939.stderr +++ b/src/test/ui/issues/issue-16939.stderr @@ -4,11 +4,11 @@ error[E0057]: this function takes 0 arguments but 1 argument was supplied LL | |t| f(t); | ^ - argument unexpected | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL +note: callable defined here + --> $DIR/issue-16939.rs:4:12 | -LL | extern "rust-call" fn call(&self, args: Args) -> Self::Output; - | ^^^^ +LL | fn _foo<F: Fn()> (f: F) { + | ^^^^ help: remove the extra argument | LL | |t| f(); diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index 4856418ed6002..3a629e1ebf472 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -2,7 +2,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: ...which immediately requires const-evaluating + checking `FOO` again note: cycle used when const-evaluating + checking `main::{constant#0}` diff --git a/src/test/ui/issues/issue-17718-const-privacy.stderr b/src/test/ui/issues/issue-17718-const-privacy.stderr index d4595be749034..133a6360bf9a0 100644 --- a/src/test/ui/issues/issue-17718-const-privacy.stderr +++ b/src/test/ui/issues/issue-17718-const-privacy.stderr @@ -20,7 +20,7 @@ note: the constant `BAR` is defined here --> $DIR/auxiliary/issue-17718-const-privacy.rs:4:1 | LL | const BAR: usize = 3; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17959.stderr b/src/test/ui/issues/issue-17959.stderr index f00356f602e93..fb795febf7954 100644 --- a/src/test/ui/issues/issue-17959.stderr +++ b/src/test/ui/issues/issue-17959.stderr @@ -7,10 +7,8 @@ LL | impl<T> Drop for G<T> { note: the implementor must specify the same requirement --> $DIR/issue-17959.rs:7:1 | -LL | / struct G<T: ?Sized> { -LL | | _ptr: *const T -LL | | } - | |_^ +LL | struct G<T: ?Sized> { + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18389.stderr b/src/test/ui/issues/issue-18389.stderr index dc476f5edc700..6ce78c45d6e5a 100644 --- a/src/test/ui/issues/issue-18389.stderr +++ b/src/test/ui/issues/issue-18389.stderr @@ -8,9 +8,7 @@ LL | / pub trait Public: Private< LL | | LL | | <Self as Public>::P, LL | | <Self as Public>::R -... | -LL | | fn call_inner(&self); -LL | | } +LL | | > { | |_^ can't leak private trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19482.stderr b/src/test/ui/issues/issue-19482.stderr index 42a5a01596905..d51cc1f081e2d 100644 --- a/src/test/ui/issues/issue-19482.stderr +++ b/src/test/ui/issues/issue-19482.stderr @@ -2,7 +2,7 @@ error[E0191]: the value of the associated type `A` (from trait `Foo`) must be sp --> $DIR/issue-19482.rs:10:16 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here ... LL | fn bar(x: &dyn Foo) {} | ^^^ help: specify the associated type: `Foo<A = Type>` diff --git a/src/test/ui/issues/issue-19692.stderr b/src/test/ui/issues/issue-19692.stderr index b412d7bc70436..9e888ed758a11 100644 --- a/src/test/ui/issues/issue-19692.stderr +++ b/src/test/ui/issues/issue-19692.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `kaname` found for struct `Homura` in the current --> $DIR/issue-19692.rs:4:40 | LL | struct Homura; - | -------------- method `kaname` not found for this + | ------------- method `kaname` not found for this struct ... LL | let Some(ref madoka) = Some(homura.kaname()); | ^^^^^^ method not found in `Homura` diff --git a/src/test/ui/issues/issue-20261.stderr b/src/test/ui/issues/issue-20261.stderr index 73468c7ca1687..9ac751e4dc437 100644 --- a/src/test/ui/issues/issue-20261.stderr +++ b/src/test/ui/issues/issue-20261.stderr @@ -3,8 +3,6 @@ error[E0282]: type annotations needed | LL | i.clone(); | ^^^^^ cannot infer type - | - = note: type must be known at this point error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.rs b/src/test/ui/issues/issue-20413.rs index a4345ccdfbe81..138a235e675e3 100644 --- a/src/test/ui/issues/issue-20413.rs +++ b/src/test/ui/issues/issue-20413.rs @@ -1,5 +1,5 @@ trait Foo { - fn answer(self); + fn answer(self); } struct NoData<T>; @@ -7,18 +7,17 @@ struct NoData<T>; impl<T> Foo for T where NoData<T>: Foo { //~^ ERROR: overflow evaluating the requirement - //~| ERROR: overflow evaluating the requirement fn answer(self) { let val: NoData<T> = NoData; } } trait Bar { - fn answer(self); + fn answer(self); } trait Baz { - fn answer(self); + fn answer(self); } struct AlmostNoData<T>(Option<T>); @@ -27,7 +26,6 @@ struct EvenLessData<T>(Option<T>); impl<T> Bar for T where EvenLessData<T>: Baz { //~^ ERROR: overflow evaluating the requirement -//~| ERROR: overflow evaluating the requirement fn answer(self) { let val: EvenLessData<T> = EvenLessData(None); } @@ -35,7 +33,6 @@ impl<T> Bar for T where EvenLessData<T>: Baz { impl<T> Baz for T where AlmostNoData<T>: Bar { //~^ ERROR: overflow evaluating the requirement -//~| ERROR: overflow evaluating the requirement fn answer(self) { let val: NoData<T> = AlmostNoData(None); } diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 2935214140419..ea493c58a33f6 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -22,102 +22,47 @@ LL | impl<T> Foo for T where NoData<T>: Foo { = note: 127 redundant requirements hidden = note: required because of the requirements on the impl of `Foo` for `NoData<T>` -error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` - --> $DIR/issue-20413.rs:8:36 - | -LL | impl<T> Foo for T where NoData<T>: Foo { - | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) -note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:8:9 - | -LL | impl<T> Foo for T where NoData<T>: Foo { - | ^^^ ^ - = note: 127 redundant requirements hidden - = note: required because of the requirements on the impl of `Foo` for `NoData<T>` - error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz` - --> $DIR/issue-20413.rs:28:42 + --> $DIR/issue-20413.rs:27: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 because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:28:9 + --> $DIR/issue-20413.rs:27:9 | LL | impl<T> Bar for T where EvenLessData<T>: Baz { | ^^^ ^ note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:36:9 + --> $DIR/issue-20413.rs:34:9 | LL | impl<T> Baz for T where AlmostNoData<T>: Bar { | ^^^ ^ = note: 126 redundant requirements hidden = note: required because of the requirements on the impl of `Baz` for `EvenLessData<T>` -error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Baz` - --> $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 because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:28:9 - | -LL | impl<T> Bar for T where EvenLessData<T>: Baz { - | ^^^ ^ -note: required because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:36:9 - | -LL | impl<T> Baz for T where AlmostNoData<T>: Bar { - | ^^^ ^ - = note: 126 redundant requirements hidden - = note: required because of the requirements on the impl of `Baz` for `EvenLessData<T>` - -error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar` - --> $DIR/issue-20413.rs:36: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 because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:36:9 - | -LL | impl<T> Baz for T where AlmostNoData<T>: Bar { - | ^^^ ^ -note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:28:9 - | -LL | impl<T> Bar for T where EvenLessData<T>: Baz { - | ^^^ ^ - = note: 126 redundant requirements hidden - = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>` - error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Bar` - --> $DIR/issue-20413.rs:36:42 + --> $DIR/issue-20413.rs:34: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 because of the requirements on the impl of `Baz` for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:36:9 + --> $DIR/issue-20413.rs:34:9 | LL | impl<T> Baz for T where AlmostNoData<T>: Bar { | ^^^ ^ note: required because of the requirements on the impl of `Bar` for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-20413.rs:28:9 + --> $DIR/issue-20413.rs:27:9 | LL | impl<T> Bar for T where EvenLessData<T>: Baz { | ^^^ ^ = note: 126 redundant requirements hidden = note: required because of the requirements on the impl of `Bar` for `AlmostNoData<T>` -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0275, E0392. For more information about an error, try `rustc --explain E0275`. diff --git a/src/test/ui/issues/issue-20714.stderr b/src/test/ui/issues/issue-20714.stderr index 456aff05750dd..2d88ce5e51107 100644 --- a/src/test/ui/issues/issue-20714.stderr +++ b/src/test/ui/issues/issue-20714.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `G` --> $DIR/issue-20714.rs:4:13 | LL | struct G; - | --------- `G` defined here + | -------- `G` defined here ... LL | let g = G(); | ^-- diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index c964dc41dceaf..22b9f5bd4cb9f 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -1,19 +1,15 @@ error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item` --> $DIR/issue-20772.rs:1:1 | -LL | / trait T : Iterator<Item=Self::Item> -LL | | -LL | | {} - | |__^ +LL | trait T : Iterator<Item=Self::Item> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which immediately requires computing the super traits of `T` with associated type name `Item` again note: cycle used when computing the super traits of `T` --> $DIR/issue-20772.rs:1:1 | -LL | / trait T : Iterator<Item=Self::Item> -LL | | -LL | | {} - | |__^ +LL | trait T : Iterator<Item=Self::Item> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2151.stderr b/src/test/ui/issues/issue-2151.stderr index e0d946205ad0a..31a8ca5fbfac8 100644 --- a/src/test/ui/issues/issue-2151.stderr +++ b/src/test/ui/issues/issue-2151.stderr @@ -3,8 +3,9 @@ error[E0282]: type annotations needed | LL | let x = panic!(); | ^ +LL | x.clone(); + | - type must be known at this point | - = note: type must be known at this point help: consider giving `x` an explicit type | LL | let x: _ = panic!(); diff --git a/src/test/ui/issues/issue-21600.stderr b/src/test/ui/issues/issue-21600.stderr index dab3c3d179725..ea304f9367b05 100644 --- a/src/test/ui/issues/issue-21600.stderr +++ b/src/test/ui/issues/issue-21600.stderr @@ -5,29 +5,26 @@ LL | fn call_it<F>(f: F) where F: Fn() { f(); } | - change this to accept `FnMut` instead of `Fn` ... LL | call_it(|| x.gen_mut()); - | ------- ^^^^^^^^^^^ cannot borrow as mutable - | | + | ------- -- ^^^^^^^^^^^ cannot borrow as mutable + | | | + | | in this closure | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/issue-21600.rs:14:17 | -LL | fn call_it<F>(f: F) where F: Fn() { f(); } - | - change this to accept `FnMut` instead of `Fn` +LL | fn call_it<F>(f: F) where F: Fn() { f(); } + | - change this to accept `FnMut` instead of `Fn` ... -LL | call_it(|| { - | _____-------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | call_it(|| x.gen()); -LL | | call_it(|| x.gen_mut()); - | | ^^ - mutable borrow occurs due to use of `x` in closure - | | | - | | cannot borrow as mutable -LL | | -LL | | -LL | | }); - | |_____- in this closure +LL | call_it(|| { + | ------- -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | call_it(|| x.gen()); +LL | call_it(|| x.gen_mut()); + | ^^ - mutable borrow occurs due to use of `x` in closure + | | + | cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-21701.stderr b/src/test/ui/issues/issue-21701.stderr index 0405ce551b0ab..ada6f44319dec 100644 --- a/src/test/ui/issues/issue-21701.stderr +++ b/src/test/ui/issues/issue-21701.stderr @@ -12,7 +12,7 @@ error[E0618]: expected function, found `Bar` --> $DIR/issue-21701.rs:9:13 | LL | struct Bar; - | ----------- `Bar` defined here + | ---------- `Bar` defined here ... LL | let f = Bar(); | ^^^-- diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr index 93c2444f884de..4909398bb848f 100644 --- a/src/test/ui/issues/issue-21950.stderr +++ b/src/test/ui/issues/issue-21950.stderr @@ -1,13 +1,11 @@ error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-21950.rs:10:25 | -LL | / trait Add<Rhs=Self> { -LL | | type Output; -LL | | } - | |_- type parameter `Rhs` must be specified for this +LL | trait Add<Rhs=Self> { + | ------------------- type parameter `Rhs` must be specified for this ... -LL | let x = &10 as &dyn Add; - | ^^^ help: set the type parameter to the desired type: `Add<Rhs>` +LL | let x = &10 as &dyn Add; + | ^^^ help: set the type parameter to the desired type: `Add<Rhs>` | = note: because of the default `Self` reference, type parameters must be specified on object types @@ -15,7 +13,7 @@ error[E0191]: the value of the associated type `Output` (from trait `Add`) must --> $DIR/issue-21950.rs:10:25 | LL | type Output; - | ------------ `Output` defined here + | ----------- `Output` defined here ... LL | let x = &10 as &dyn Add; | ^^^ help: specify the associated type: `Add<Output = Type>` diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr index dfabde9abc978..4e010a13653e7 100644 --- a/src/test/ui/issues/issue-21974.stderr +++ b/src/test/ui/issues/issue-21974.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo` --> $DIR/issue-21974.rs:11:19 | LL | where &'a T : Foo, - | ^^^ cannot infer type for reference `&'a T` + | ^^^ | = note: cannot satisfy `&'a T: Foo` diff --git a/src/test/ui/issues/issue-22034.stderr b/src/test/ui/issues/issue-22034.stderr index edcd21ebd6b9b..b32de5b24b924 100644 --- a/src/test/ui/issues/issue-22034.stderr +++ b/src/test/ui/issues/issue-22034.stderr @@ -6,7 +6,7 @@ LL | &mut *(ptr as *mut dyn Fn()) | = help: the trait `Fn<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` - = note: required for the cast to the object type `dyn Fn()` + = note: required for the cast from `()` to the object type `dyn Fn()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22370.stderr b/src/test/ui/issues/issue-22370.stderr index 4da346f56ab76..cd27c4e4e4edf 100644 --- a/src/test/ui/issues/issue-22370.stderr +++ b/src/test/ui/issues/issue-22370.stderr @@ -2,7 +2,7 @@ error[E0393]: the type parameter `T` must be explicitly specified --> $DIR/issue-22370.rs:3:14 | LL | trait A<T=Self> {} - | ------------------ type parameter `T` must be specified for this + | --------------- type parameter `T` must be specified for this LL | LL | fn f(a: &dyn A) {} | ^ help: set the type parameter to the desired type: `A<T>` diff --git a/src/test/ui/issues/issue-22434.stderr b/src/test/ui/issues/issue-22434.stderr index 79b9d85610bce..b97fa2503b8a8 100644 --- a/src/test/ui/issues/issue-22434.stderr +++ b/src/test/ui/issues/issue-22434.stderr @@ -2,7 +2,7 @@ error[E0191]: the value of the associated type `A` (from trait `Foo`) must be sp --> $DIR/issue-22434.rs:5:23 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here ... LL | type I<'a> = &'a (dyn Foo + 'a); | ^^^ help: specify the associated type: `Foo<A = Type>` diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index cd96646d751f2..a84cb7d8c5922 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -10,7 +10,7 @@ note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for | LL | impl<'b, P> Wrap<'b> for Wrapper<P> | ^^^^^^^^ ^^^^^^^^^^ - = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` + = note: required for the cast from `Wrapper<P>` to the object type `dyn for<'b> Wrap<'b>` help: consider further restricting the associated type | LL | fn push_process<P>(process: P) where P: Process<'static>, <P as Process<'_>>::Item: Iterator { diff --git a/src/test/ui/issues/issue-22933-2.stderr b/src/test/ui/issues/issue-22933-2.stderr index 0bfbf538486de..1a0e87e15d6bc 100644 --- a/src/test/ui/issues/issue-22933-2.stderr +++ b/src/test/ui/issues/issue-22933-2.stderr @@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `PIE` found for enum `Deliciou --> $DIR/issue-22933-2.rs:4:55 | LL | enum Delicious { - | -------------- variant or associated item `PIE` not found here + | -------------- variant or associated item `PIE` not found for this enum ... LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, | ^^^ diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr index 401086b204435..7b9a1634a0d4c 100644 --- a/src/test/ui/issues/issue-23041.stderr +++ b/src/test/ui/issues/issue-23041.stderr @@ -1,8 +1,13 @@ error[E0282]: type annotations needed - --> $DIR/issue-23041.rs:6:22 + --> $DIR/issue-23041.rs:6:7 | LL | b.downcast_ref::<fn(_)->_>(); - | ^^^^^^^^ cannot infer type + | ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref` + | +help: consider specifying the generic arguments + | +LL | b.downcast_ref::<fn(_) -> _>(); + | ~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23173.stderr b/src/test/ui/issues/issue-23173.stderr index 89f70fda786ea..d07d1a7caaf24 100644 --- a/src/test/ui/issues/issue-23173.stderr +++ b/src/test/ui/issues/issue-23173.stderr @@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `Homura` found for enum `Token --> $DIR/issue-23173.rs:9:23 | LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ } - | ---------- variant or associated item `Homura` not found here + | ---------- variant or associated item `Homura` not found for this enum ... LL | use_token(&Token::Homura); | ^^^^^^ variant or associated item not found in `Token` @@ -11,7 +11,7 @@ error[E0599]: no function or associated item named `method` found for struct `St --> $DIR/issue-23173.rs:10:13 | LL | struct Struct { - | ------------- function or associated item `method` not found for this + | ------------- function or associated item `method` not found for this struct ... LL | Struct::method(); | ^^^^^^ function or associated item not found in `Struct` @@ -20,7 +20,7 @@ error[E0599]: no function or associated item named `method` found for struct `St --> $DIR/issue-23173.rs:11:13 | LL | struct Struct { - | ------------- function or associated item `method` not found for this + | ------------- function or associated item `method` not found for this struct ... LL | Struct::method; | ^^^^^^ function or associated item not found in `Struct` @@ -29,7 +29,7 @@ error[E0599]: no associated item named `Assoc` found for struct `Struct` in the --> $DIR/issue-23173.rs:12:13 | LL | struct Struct { - | ------------- associated item `Assoc` not found for this + | ------------- associated item `Assoc` not found for this struct ... LL | Struct::Assoc; | ^^^^^ associated item not found in `Struct` diff --git a/src/test/ui/issues/issue-23217.stderr b/src/test/ui/issues/issue-23217.stderr index a81b459a34cbe..5d3d8a4f808a8 100644 --- a/src/test/ui/issues/issue-23217.stderr +++ b/src/test/ui/issues/issue-23217.stderr @@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `A` found for enum `SomeEnum` --> $DIR/issue-23217.rs:2:19 | LL | pub enum SomeEnum { - | ----------------- variant or associated item `A` not found here + | ----------------- variant or associated item `A` not found for this enum LL | B = SomeEnum::A, | ^ | | diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index 1a07d4a95bcfa..dcb99605da012 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -2,19 +2,19 @@ error[E0391]: cycle detected when const-evaluating + checking `A` --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | note: ...which requires const-evaluating + checking `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `A`, completing the cycle note: cycle used when simplifying constant for the type system `A` --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr index 4e3cb88297d3b..863993f450904 100644 --- a/src/test/ui/issues/issue-24013.stderr +++ b/src/test/ui/issues/issue-24013.stderr @@ -1,8 +1,13 @@ error[E0282]: type annotations needed - --> $DIR/issue-24013.rs:5:20 + --> $DIR/issue-24013.rs:5:13 | LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; - | ^^^^^^ cannot infer type + | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap` + | +help: consider specifying the generic arguments + | +LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; + | ~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr index 4622501f33eda..a42e35c4cad5c 100644 --- a/src/test/ui/issues/issue-24036.stderr +++ b/src/test/ui/issues/issue-24036.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/issue-24036.rs:3:9 | LL | let mut x = |c| c + 1; - | --------- the expected closure + | --- the expected closure LL | x = |c| c + 1; | ^^^^^^^^^ expected closure, found a different closure | - = note: expected closure `[closure@$DIR/issue-24036.rs:2:17: 2:26]` - found closure `[closure@$DIR/issue-24036.rs:3:9: 3:18]` + = note: expected closure `[closure@$DIR/issue-24036.rs:2:17: 2:20]` + found closure `[closure@$DIR/issue-24036.rs:3:9: 3:12]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr index fa59da852f901..8f3b2ac73199c 100644 --- a/src/test/ui/issues/issue-24424.stderr +++ b/src/test/ui/issues/issue-24424.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `T0: Trait0<'l0>` --> $DIR/issue-24424.rs:4:57 | LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} - | ^^^^^^^^^^^ cannot infer type for type parameter `T0` + | ^^^^^^^^^^^ | = note: cannot satisfy `T0: Trait0<'l0>` diff --git a/src/test/ui/issues/issue-25368.rs b/src/test/ui/issues/issue-25368.rs index b7f0f613e8091..4be83457f7a8b 100644 --- a/src/test/ui/issues/issue-25368.rs +++ b/src/test/ui/issues/issue-25368.rs @@ -5,10 +5,10 @@ use std::marker::PhantomData; struct Foo<T> {foo: PhantomData<T>} fn main() { - let (tx, rx) = //~ ERROR type annotations needed + let (tx, rx) = channel(); - // FIXME(#89862): Suggest adding a generic argument to `channel` instead spawn(move || { tx.send(Foo{ foo: PhantomData }); + //~^ ERROR type annotations needed }); } diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index ffcb73849527f..e6ed3aac71032 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,13 +1,13 @@ -error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)` - --> $DIR/issue-25368.rs:8:9 +error[E0282]: type annotations needed + --> $DIR/issue-25368.rs:11:27 | -LL | let (tx, rx) = - | ^^^^^^^^ +LL | tx.send(Foo{ foo: PhantomData }); + | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData` | -help: consider giving this pattern a type, where the type for type parameter `T` is specified +help: consider specifying the generic argument | -LL | let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) = - | +++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | tx.send(Foo{ foo: PhantomData::<T> }); + | +++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25901.stderr b/src/test/ui/issues/issue-25901.stderr index 5c35250bc3f39..e933745c44e87 100644 --- a/src/test/ui/issues/issue-25901.stderr +++ b/src/test/ui/issues/issue-25901.stderr @@ -9,7 +9,7 @@ note: deref defined here --> $DIR/issue-25901.rs:10:5 | LL | type Target = B; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ note: impl defined here, but it is not `const` --> $DIR/issue-25901.rs:9:1 | diff --git a/src/test/ui/issues/issue-26094.rs b/src/test/ui/issues/issue-26094.rs index 981c3abb4bae0..df8c2f739108d 100644 --- a/src/test/ui/issues/issue-26094.rs +++ b/src/test/ui/issues/issue-26094.rs @@ -1,6 +1,6 @@ macro_rules! some_macro { ($other: expr) => ({ - $other(None) //~ NOTE argument unexpected + $other(None) //~ NOTE argument of type `Option<_>` unexpected }) } diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr index 1013518e1dad3..881a6e538ee44 100644 --- a/src/test/ui/issues/issue-26094.stderr +++ b/src/test/ui/issues/issue-26094.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/issue-26094.rs:10:17 | LL | $other(None) - | ---- argument unexpected + | ---- argument of type `Option<_>` unexpected ... LL | some_macro!(some_function); | ^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index 4aec27f9684f9..c6e703f4876f8 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -2,9 +2,8 @@ error[E0072]: recursive type `Pong` has infinite size --> $DIR/issue-2718-a.rs:8:5 | LL | pub struct Pong(SendPacket<Ping>); - | ^^^^^^^^^^^^^^^^----------------^^ - | | | - | | recursive without indirection + | ^^^^^^^^^^^^^^^ ---------------- recursive without indirection + | | | recursive type has infinite size | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Pong` representable diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index b3bc946292f70..b5a2b2f55a6d4 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `C` in the current scope --> $DIR/issue-2823.rs:13:16 | LL | struct C { - | -------- method `clone` not found for this + | -------- method `clone` not found for this struct ... LL | let _d = c.clone(); | ^^^^^ method not found in `C` diff --git a/src/test/ui/issues/issue-28971.stderr b/src/test/ui/issues/issue-28971.stderr index 2736ee881d564..2eb8a1c2653c8 100644 --- a/src/test/ui/issues/issue-28971.stderr +++ b/src/test/ui/issues/issue-28971.stderr @@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `Baz` found for enum `Foo` in --> $DIR/issue-28971.rs:7:18 | LL | enum Foo { - | -------- variant or associated item `Baz` not found here + | -------- variant or associated item `Baz` not found for this enum ... LL | Foo::Baz(..) => (), | ^^^ diff --git a/src/test/ui/issues/issue-3044.rs b/src/test/ui/issues/issue-3044.rs index 7363cae8370ab..7c626a01b1298 100644 --- a/src/test/ui/issues/issue-3044.rs +++ b/src/test/ui/issues/issue-3044.rs @@ -1,7 +1,6 @@ fn main() { let needlesArr: Vec<char> = vec!['a', 'f']; needlesArr.iter().fold(|x, y| { + //~^ ERROR this function takes 2 arguments but 1 argument was supplied }); - //~^^ ERROR mismatched types - //~| ERROR this function takes 2 arguments but 1 argument was supplied } diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr index 6dbe6b59391e3..a4c455ca1927e 100644 --- a/src/test/ui/issues/issue-3044.stderr +++ b/src/test/ui/issues/issue-3044.stderr @@ -1,19 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/issue-3044.rs:3:35 - | -LL | needlesArr.iter().fold(|x, y| { - | ___________________________________^ -LL | | }); - | |_____^ expected closure, found `()` - | - = note: expected closure `[closure@$DIR/issue-3044.rs:3:28: 4:6]` - found unit type `()` - error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-3044.rs:3:23 | LL | needlesArr.iter().fold(|x, y| { | _______________________^^^^- +LL | | LL | | }); | |______- an argument is missing | @@ -25,10 +15,10 @@ LL | fn fold<B, F>(mut self, init: B, mut f: F) -> B help: provide the argument | LL ~ needlesArr.iter().fold(|x, y| { +LL + LL ~ }, /* value */); | -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0061, E0308. -For more information about an error, try `rustc --explain E0061`. +For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 982b6118ce659..68337a715e14f 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item == &_` +error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_` --> $DIR/issue-31173.rs:10:10 | LL | .cloned() @@ -12,11 +12,11 @@ note: required by a bound in `cloned` LL | Self: Sized + Iterator<Item = &'a T>, | ^^^^^^^^^^^^ required by this bound in `cloned` -error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>`, but its trait bounds were not satisfied +error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied --> $DIR/issue-31173.rs:12:10 | LL | .collect(); - | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds | ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL | @@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> { | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | = note: the following trait bounds were not satisfied: - `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item = &_` - which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` - `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` - which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` + `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_` + which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` + `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` + which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-33504.stderr b/src/test/ui/issues/issue-33504.stderr index ec15525ed0601..d9e7c3b16e76e 100644 --- a/src/test/ui/issues/issue-33504.stderr +++ b/src/test/ui/issues/issue-33504.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-33504.rs:7:13 | LL | struct Test; - | ------------ unit struct defined here + | ----------- unit struct defined here ... LL | let Test = 1; | ^^^^ - this expression has type `{integer}` diff --git a/src/test/ui/issues/issue-35241.stderr b/src/test/ui/issues/issue-35241.stderr index 319886f878384..a66289a1cf8eb 100644 --- a/src/test/ui/issues/issue-35241.stderr +++ b/src/test/ui/issues/issue-35241.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-35241.rs:3:20 | LL | struct Foo(u32); - | ---------------- fn(u32) -> Foo {Foo} defined here + | ---------- fn(u32) -> Foo {Foo} defined here LL | LL | fn test() -> Foo { Foo } | --- ^^^ expected struct `Foo`, found fn item diff --git a/src/test/ui/issues/issue-35976.stderr b/src/test/ui/issues/issue-35976.stderr index f9b9b7dbd34bb..fe16f97b9d0f5 100644 --- a/src/test/ui/issues/issue-35976.stderr +++ b/src/test/ui/issues/issue-35976.stderr @@ -6,11 +6,6 @@ LL | fn wait(&self) where Self: Sized; ... LL | arg.wait(); | ^^^^ - | -help: another candidate was found in the following trait, perhaps add a `use` for it: - | -LL | use private::Future; - | error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37515.stderr b/src/test/ui/issues/issue-37515.stderr index c9bb4c10010f5..f1e83ca74d8e9 100644 --- a/src/test/ui/issues/issue-37515.stderr +++ b/src/test/ui/issues/issue-37515.stderr @@ -1,8 +1,8 @@ warning: type alias `Z` is never used - --> $DIR/issue-37515.rs:5:1 + --> $DIR/issue-37515.rs:5:6 | LL | type Z = dyn for<'x> Send; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/issue-37515.rs:3:9 diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index cd84b6ef48471..e9f50b41f6acd 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -1,17 +1,12 @@ error[E0308]: method not compatible with trait --> $DIR/issue-37884.rs:6:5 | -LL | / fn next(&'a mut self) -> Option<Self::Item> -LL | | -LL | | -LL | | { -LL | | Some(&mut self.0) -LL | | } - | |_____^ lifetime mismatch +LL | fn next(&'a mut self) -> Option<Self::Item> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>` found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>` -note: the anonymous lifetime #1 defined here... +note: the anonymous lifetime as defined here... --> $DIR/issue-37884.rs:6:5 | LL | fn next(&'a mut self) -> Option<Self::Item> diff --git a/src/test/ui/issues/issue-38857.stderr b/src/test/ui/issues/issue-38857.stderr index e9d229f74e8d4..23090c1ed7866 100644 --- a/src/test/ui/issues/issue-38857.stderr +++ b/src/test/ui/issues/issue-38857.stderr @@ -14,7 +14,7 @@ note: the module `sys` is defined here --> $SRC_DIR/std/src/lib.rs:LL:COL | LL | mod sys; - | ^^^^^^^^ + | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38919.stderr b/src/test/ui/issues/issue-38919.stderr index 0022065a32c3d..f9ab8a5150716 100644 --- a/src/test/ui/issues/issue-38919.stderr +++ b/src/test/ui/issues/issue-38919.stderr @@ -1,6 +1,8 @@ error[E0599]: no associated item named `Item` found for type parameter `T` in the current scope --> $DIR/issue-38919.rs:2:8 | +LL | fn foo<T: Iterator>() { + | - associated item `Item` not found for this type parameter LL | T::Item; | ^^^^ associated item not found in `T` diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr index 017dd831f712a..fd694df30457e 100644 --- a/src/test/ui/issues/issue-41880.stderr +++ b/src/test/ui/issues/issue-41880.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `iter` found for struct `Iterate` in the current s --> $DIR/issue-41880.rs:27:24 | LL | pub struct Iterate<T, F> { - | ------------------------ method `iter` not found for this + | ------------------------ method `iter` not found for this struct ... LL | println!("{:?}", a.iter().take(10).collect::<Vec<usize>>()); - | ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` + | ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:27]>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4265.stderr b/src/test/ui/issues/issue-4265.stderr index acdf963ed3bd7..27e83d4957493 100644 --- a/src/test/ui/issues/issue-4265.stderr +++ b/src/test/ui/issues/issue-4265.stderr @@ -1,14 +1,11 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/issue-4265.rs:10:5 | -LL | / fn bar() { -LL | | Foo { baz: 0 }.bar(); -LL | | } - | |_____- previous definition of `bar` here -LL | -LL | / fn bar() { -LL | | } - | |_____^ duplicate definition +LL | fn bar() { + | -------- previous definition of `bar` here +... +LL | fn bar() { + | ^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4335.stderr b/src/test/ui/issues/issue-4335.stderr index fa3b58e127937..ecc1fa5239892 100644 --- a/src/test/ui/issues/issue-4335.stderr +++ b/src/test/ui/issues/issue-4335.stderr @@ -4,9 +4,8 @@ error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMu LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> { | - captured outer variable LL | id(Box::new(|| *v)) - | ---^^ - | | | - | | move occurs because `*v` has type `T`, which does not implement the `Copy` trait + | -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait + | | | captured by this `FnMut` closure error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43355.stderr b/src/test/ui/issues/issue-43355.stderr index 23d8ed1848f59..531130fecab1e 100644 --- a/src/test/ui/issues/issue-43355.stderr +++ b/src/test/ui/issues/issue-43355.stderr @@ -2,7 +2,7 @@ error[E0119]: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` --> $DIR/issue-43355.rs:13:1 | LL | impl<X, T> Trait1<X> for T where T: Trait2<X> { - | --------------------------------------------- first implementation here + | -------------------------- first implementation here ... LL | impl<X> Trait1<Box<X>> for A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` diff --git a/src/test/ui/issues/issue-46771.stderr b/src/test/ui/issues/issue-46771.stderr index a37b56489595d..512827b2dbdcd 100644 --- a/src/test/ui/issues/issue-46771.stderr +++ b/src/test/ui/issues/issue-46771.stderr @@ -2,7 +2,7 @@ error[E0618]: expected function, found `Foo` --> $DIR/issue-46771.rs:3:23 | LL | struct Foo; - | ----------- `Foo` defined here + | ---------- `Foo` defined here LL | (1 .. 2).find(|_| Foo(0) == 0); | ^^^--- | | diff --git a/src/test/ui/issues/issue-47486.stderr b/src/test/ui/issues/issue-47486.stderr index ca57b2d7e01d2..b45f57b7b846b 100644 --- a/src/test/ui/issues/issue-47486.stderr +++ b/src/test/ui/issues/issue-47486.stderr @@ -1,3 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/issue-47486.rs:2:10 + | +LL | () < std::mem::size_of::<_>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize` + error[E0282]: type annotations needed --> $DIR/issue-47486.rs:3:11 | @@ -9,12 +15,6 @@ help: consider specifying the generic argument LL | [0u8; std::mem::size_of::<_>()]; | ~~~~~ -error[E0308]: mismatched types - --> $DIR/issue-47486.rs:2:10 - | -LL | () < std::mem::size_of::<_>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0282, E0308. diff --git a/src/test/ui/issues/issue-47511.rs b/src/test/ui/issues/issue-47511.rs index 98c141b6c6a1d..eb4860e75d758 100644 --- a/src/test/ui/issues/issue-47511.rs +++ b/src/test/ui/issues/issue-47511.rs @@ -1,5 +1,5 @@ // check-fail -// known-bug +// known-bug: #47511 // Regression test for #47511: anonymous lifetimes can appear // unconstrained in a return type, but only if they appear just once diff --git a/src/test/ui/issues/issue-48838.stderr b/src/test/ui/issues/issue-48838.stderr index 712a7bc33f840..3502af7028baa 100644 --- a/src/test/ui/issues/issue-48838.stderr +++ b/src/test/ui/issues/issue-48838.stderr @@ -5,7 +5,7 @@ LL | Square = |x| x, | ^^^^^ expected `isize`, found closure | = note: expected type `isize` - found closure `[closure@$DIR/issue-48838.rs:2:14: 2:19]` + found closure `[closure@$DIR/issue-48838.rs:2:14: 2:17]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index b4cebe2a68b57..aab19a699ace0 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | LL | fn main() { foo(5, 6) } - | ^^^ - argument unexpected + | ^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/issue-4935.rs:3:4 diff --git a/src/test/ui/issues/issue-4968.stderr b/src/test/ui/issues/issue-4968.stderr index 57ff7fe09e5b9..bbaca4ed28f5b 100644 --- a/src/test/ui/issues/issue-4968.stderr +++ b/src/test/ui/issues/issue-4968.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-4968.rs:5:16 | LL | const A: (isize,isize) = (4,2); - | ------------------------------- constant defined here + | ---------------------- constant defined here LL | fn main() { LL | match 42 { A => () } | -- ^ diff --git a/src/test/ui/issues/issue-50600.stderr b/src/test/ui/issues/issue-50600.stderr index 08d9a8399200a..7fea7e5c0985e 100644 --- a/src/test/ui/issues/issue-50600.stderr +++ b/src/test/ui/issues/issue-50600.stderr @@ -5,7 +5,7 @@ LL | fn([u8; |x: u8| {}]), | ^^^^^^^^^^ expected `usize`, found closure | = note: expected type `usize` - found closure `[closure@$DIR/issue-50600.rs:2:13: 2:23]` + found closure `[closure@$DIR/issue-50600.rs:2:13: 2:20]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50688.stderr b/src/test/ui/issues/issue-50688.stderr index 1f348c4cf1f66..6973ad271b40d 100644 --- a/src/test/ui/issues/issue-50688.stderr +++ b/src/test/ui/issues/issue-50688.stderr @@ -5,7 +5,7 @@ LL | [1; || {}]; | ^^^^^ expected `usize`, found closure | = note: expected type `usize` - found closure `[closure@$DIR/issue-50688.rs:2:9: 2:14]` + found closure `[closure@$DIR/issue-50688.rs:2:9: 2:11]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51116.rs b/src/test/ui/issues/issue-51116.rs index c979c7b2cdd76..4c21cbfc61d43 100644 --- a/src/test/ui/issues/issue-51116.rs +++ b/src/test/ui/issues/issue-51116.rs @@ -5,7 +5,6 @@ fn main() { *tile = 0; //~^ ERROR type annotations needed //~| NOTE cannot infer type - //~| NOTE type must be known at this point } } diff --git a/src/test/ui/issues/issue-51116.stderr b/src/test/ui/issues/issue-51116.stderr index 399b421ab163e..c07f8735eb2c7 100644 --- a/src/test/ui/issues/issue-51116.stderr +++ b/src/test/ui/issues/issue-51116.stderr @@ -3,8 +3,6 @@ error[E0282]: type annotations needed | LL | *tile = 0; | ^^^^^ cannot infer type - | - = note: type must be known at this point error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51154.stderr b/src/test/ui/issues/issue-51154.stderr index f2cbc3e6feb78..44ec626dea5fc 100644 --- a/src/test/ui/issues/issue-51154.stderr +++ b/src/test/ui/issues/issue-51154.stderr @@ -9,7 +9,7 @@ LL | let _: Box<F> = Box::new(|| ()); | arguments to this function are incorrect | = note: expected type parameter `F` - found closure `[closure@$DIR/issue-51154.rs:2:30: 2:35]` + found closure `[closure@$DIR/issue-51154.rs:2:30: 2:32]` = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F` note: associated function defined here --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/src/test/ui/issues/issue-51515.rs b/src/test/ui/issues/issue-51515.rs index 54fd176de75f0..797c1085d517b 100644 --- a/src/test/ui/issues/issue-51515.rs +++ b/src/test/ui/issues/issue-51515.rs @@ -5,8 +5,6 @@ fn main() { *foo = 32; //~^ ERROR cannot assign to `*foo`, which is behind a `&` reference let bar = foo; - //~^ HELP consider changing this to be a mutable reference - //~| SUGGESTION &mut i32 *bar = 64; //~^ ERROR cannot assign to `*bar`, which is behind a `&` reference } diff --git a/src/test/ui/issues/issue-51515.stderr b/src/test/ui/issues/issue-51515.stderr index 62bb462faa208..067bdef8b6746 100644 --- a/src/test/ui/issues/issue-51515.stderr +++ b/src/test/ui/issues/issue-51515.stderr @@ -8,11 +8,10 @@ LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*bar`, which is behind a `&` reference - --> $DIR/issue-51515.rs:10:5 + --> $DIR/issue-51515.rs:8:5 | LL | let bar = foo; - | --- help: consider changing this to be a mutable reference: `&mut i32` -... + | --- consider changing this binding's type to be: `&mut i32` LL | *bar = 64; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written diff --git a/src/test/ui/issues/issue-54044.stderr b/src/test/ui/issues/issue-54044.stderr index 0200a6a629d8f..100965de1aa84 100644 --- a/src/test/ui/issues/issue-54044.stderr +++ b/src/test/ui/issues/issue-54044.stderr @@ -1,11 +1,11 @@ -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/issue-54044.rs:3:1 | LL | #[cold] | ^^^^^^^ ... LL | struct Foo; - | ----------- not a function + | ----------- not a function definition | note: the lint level is defined here --> $DIR/issue-54044.rs:1:9 @@ -14,14 +14,14 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/issue-54044.rs:9:5 | LL | #[cold] | ^^^^^^^ ... LL | 5; - | - not a function + | - not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/issues/issue-64430.stderr b/src/test/ui/issues/issue-64430.stderr index e7a244e9df576..b6b1f3a66c785 100644 --- a/src/test/ui/issues/issue-64430.stderr +++ b/src/test/ui/issues/issue-64430.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `bar` found for struct `Foo` in the current scope --> $DIR/issue-64430.rs:7:9 | LL | pub struct Foo; - | --------------- method `bar` not found for this + | -------------- method `bar` not found for this struct ... LL | Foo.bar() | ^^^ method not found in `Foo` diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs index 98192dae20da8..ec1997ccd5d66 100644 --- a/src/test/ui/issues/issue-67552.rs +++ b/src/test/ui/issues/issue-67552.rs @@ -1,4 +1,5 @@ // build-fail +// compile-flags: -Copt-level=0 // normalize-stderr-test: ".nll/" -> "/" fn main() { diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index cf05a72e921e0..2968be7c71fb5 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,11 +1,11 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>` - --> $DIR/issue-67552.rs:28:9 + --> $DIR/issue-67552.rs:29:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:21:1 + --> $DIR/issue-67552.rs:22:1 | LL | / fn rec<T>(mut it: T) LL | | where diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr index 6c4eafbc8b3a1..9be6c2f8564ff 100644 --- a/src/test/ui/issues/issue-69455.stderr +++ b/src/test/ui/issues/issue-69455.stderr @@ -14,7 +14,9 @@ error[E0283]: type annotations needed --> $DIR/issue-69455.rs:29:41 | LL | println!("{}", 23u64.test(xs.iter().sum())); - | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum` + | ---- ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum` + | | + | type must be known at this point | note: multiple `impl`s satisfying `u64: Test<_>` found --> $DIR/issue-69455.rs:11:1 diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index cb5b397849c06..2c2cd5c5244cf 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -8,7 +8,7 @@ error[E0046]: not all trait items implemented, missing: `MyA` --> $DIR/issue-69602-type-err-during-codegen-ice.rs:16:1 | LL | type MyA: TraitA; - | ----------------- `MyA` from trait + | ---------------- `MyA` from trait ... LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation diff --git a/src/test/ui/issues/issue-69683.stderr b/src/test/ui/issues/issue-69683.stderr index 9c71ecffa2682..193de1a35cf1a 100644 --- a/src/test/ui/issues/issue-69683.stderr +++ b/src/test/ui/issues/issue-69683.stderr @@ -1,8 +1,14 @@ -error[E0284]: type annotations needed: cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]` +error[E0284]: type annotations needed --> $DIR/issue-69683.rs:30:10 | LL | 0u16.foo(b); - | ^^^ cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]` + | ^^^ + | + = note: cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]` +help: try using a fully qualified path to specify the expected types + | +LL | <u16 as Foo<I>>::foo(0u16, b); + | +++++++++++++++++++++ ~ error[E0283]: type annotations needed --> $DIR/issue-69683.rs:30:10 diff --git a/src/test/ui/issues/issue-7013.stderr b/src/test/ui/issues/issue-7013.stderr index 98ed67507b1d8..f6cb1cbdc11c6 100644 --- a/src/test/ui/issues/issue-7013.stderr +++ b/src/test/ui/issues/issue-7013.stderr @@ -11,7 +11,7 @@ note: required because it appears within the type `B` | LL | struct B { | ^ - = note: required for the cast to the object type `dyn Foo + Send` + = note: required for the cast from `B` to the object type `dyn Foo + Send` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-71584.stderr b/src/test/ui/issues/issue-71584.stderr index 1c216e6498295..6ddb7657301cd 100644 --- a/src/test/ui/issues/issue-71584.stderr +++ b/src/test/ui/issues/issue-71584.stderr @@ -1,8 +1,16 @@ -error[E0284]: type annotations needed: cannot satisfy `<u64 as Rem<_>>::Output == u64` - --> $DIR/issue-71584.rs:4:11 +error[E0284]: type annotations needed + --> $DIR/issue-71584.rs:4:15 | LL | d = d % n.into(); - | ^ cannot satisfy `<u64 as Rem<_>>::Output == u64` + | - ^^^^ + | | + | type must be known at this point + | + = note: cannot satisfy `<u64 as Rem<_>>::Output == u64` +help: try using a fully qualified path to specify the expected types + | +LL | d = d % <u32 as Into<T>>::into(n); + | +++++++++++++++++++++++ ~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-73112.stderr b/src/test/ui/issues/issue-73112.stderr index 5a548378c2687..4b8b979665cc3 100644 --- a/src/test/ui/issues/issue-73112.stderr +++ b/src/test/ui/issues/issue-73112.stderr @@ -1,19 +1,14 @@ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type --> $DIR/issue-73112.rs:9:5 | -LL | / struct SomeStruct { -LL | | -LL | | page_table: PageTable, -LL | | } - | |_____^ +LL | struct SomeStruct { + | ^^^^^^^^^^^^^^^^^ | note: `PageTable` has a `#[repr(align)]` attribute --> $DIR/auxiliary/issue-73112.rs:8:1 | -LL | / pub struct PageTable { -LL | | entries: [PageTableEntry; 512], -LL | | } - | |_^ +LL | pub struct PageTable { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr index fb8ed43674f28..13749804796b2 100644 --- a/src/test/ui/issues/issue-76191.stderr +++ b/src/test/ui/issues/issue-76191.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-76191.rs:13:9 | LL | const RANGE: RangeInclusive<i32> = 0..=255; - | ------------------------------------------- constant defined here + | -------------------------------- constant defined here ... LL | match n { | - this expression has type `i32` @@ -23,7 +23,7 @@ error[E0308]: mismatched types --> $DIR/issue-76191.rs:15:9 | LL | const RANGE2: RangeInclusive<i32> = panic!(); - | --------------------------------------------- constant defined here + | --------------------------------- constant defined here ... LL | match n { | - this expression has type `i32` diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index c986e47fb5589..b4c877a2d74a4 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -21,10 +21,10 @@ error[E0046]: not all trait items implemented, missing: `VAL` --> $DIR/issue-77919.rs:12:1 | LL | const VAL: T; - | ------------- `VAL` from trait + | ------------ `VAL` from trait ... LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation error: constant expression depends on a generic parameter --> $DIR/issue-77919.rs:2:9 diff --git a/src/test/ui/issues/issue-7813.stderr b/src/test/ui/issues/issue-7813.stderr index 3aee61bd5a54c..2a747f679a84d 100644 --- a/src/test/ui/issues/issue-7813.stderr +++ b/src/test/ui/issues/issue-7813.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `&[_; 0]` --> $DIR/issue-7813.rs:2:9 | LL | let v = &[]; - | ^ + | ^ --- type must be known at this point | help: consider giving `v` an explicit type, where the placeholders `_` are specified | diff --git a/src/test/ui/issues/issue-78957.stderr b/src/test/ui/issues/issue-78957.stderr index fa2eaab5b417b..45fa69d6fd708 100644 --- a/src/test/ui/issues/issue-78957.stderr +++ b/src/test/ui/issues/issue-78957.stderr @@ -4,11 +4,11 @@ error[E0518]: attribute should be applied to function or closure LL | pub struct Foo<#[inline] const N: usize>; | ^^^^^^^^^ -------------- not a function or closure -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/issue-78957.rs:7:16 | LL | pub struct Bar<#[cold] const N: usize>; - | ^^^^^^^ -------------- not a function + | ^^^^^^^ -------------- not a function definition | note: the lint level is defined here --> $DIR/issue-78957.rs:1:9 @@ -29,11 +29,11 @@ error[E0518]: attribute should be applied to function or closure LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); | ^^^^^^^^^ -- not a function or closure -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/issue-78957.rs:15:17 | LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); - | ^^^^^^^ -- not a function + | ^^^^^^^ -- not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -49,11 +49,11 @@ error[E0518]: attribute should be applied to function or closure LL | pub struct Foo3<#[inline] T>(PhantomData<T>); | ^^^^^^^^^ - not a function or closure -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/issue-78957.rs:23:17 | LL | pub struct Bar3<#[cold] T>(PhantomData<T>); - | ^^^^^^^ - not a function + | ^^^^^^^ - not a function definition | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/src/test/ui/issues/issue-7950.stderr b/src/test/ui/issues/issue-7950.stderr index 73e13c65cf37f..b8b0eb310cf3e 100644 --- a/src/test/ui/issues/issue-7950.stderr +++ b/src/test/ui/issues/issue-7950.stderr @@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `bar` found for struct `Foo` --> $DIR/issue-7950.rs:6:10 | LL | struct Foo; - | ----------- function or associated item `bar` not found for this + | ---------- function or associated item `bar` not found for this struct ... LL | Foo::bar(); | ^^^ function or associated item not found in `Foo` diff --git a/src/test/ui/keyword/keyword-self-as-type-param.stderr b/src/test/ui/keyword/keyword-self-as-type-param.stderr index fd101b32b4c9c..419652e13492f 100644 --- a/src/test/ui/keyword/keyword-self-as-type-param.stderr +++ b/src/test/ui/keyword/keyword-self-as-type-param.stderr @@ -18,9 +18,8 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/keyword-self-as-type-param.rs:3:1 | LL | struct Foo<Self>(Self); - | ^^^^^^^^^^^^^^^^^----^^ - | | | - | | recursive without indirection + | ^^^^^^^^^^^^^^^^ ---- recursive without indirection + | | | recursive type has infinite size | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index 32759d2fa0ebd..902349135c549 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -9,7 +9,7 @@ note: required because of the requirements on the impl of `Gettable<T>` for `S<T | LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ^^^^^^^^^^^ ^^^^ - = note: required for the cast to the object type `dyn Gettable<T>` + = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn f<T: std::marker::Send>(val: T) { @@ -26,7 +26,7 @@ note: required because of the requirements on the impl of `Gettable<T>` for `S<T | LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ^^^^^^^^^^^ ^^^^ - = note: required for the cast to the object type `dyn Gettable<T>` + = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn f<T: std::marker::Copy>(val: T) { @@ -43,7 +43,7 @@ note: required because of the requirements on the impl of `Gettable<T>` for `S<T | LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ^^^^^^^^^^^ ^^^^ - = note: required for the cast to the object type `dyn Gettable<T>` + = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn g<T: std::marker::Send>(val: T) { @@ -60,7 +60,7 @@ note: required because of the requirements on the impl of `Gettable<T>` for `S<T | LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ^^^^^^^^^^^ ^^^^ - = note: required for the cast to the object type `dyn Gettable<T>` + = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn g<T: std::marker::Copy>(val: T) { @@ -78,7 +78,7 @@ note: required because of the requirements on the impl of `Gettable<String>` for | LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ^^^^^^^^^^^ ^^^^ - = note: required for the cast to the object type `dyn Gettable<String>` + = note: required for the cast from `S<String>` to the object type `dyn Gettable<String>` error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:43:37 @@ -92,7 +92,7 @@ note: required because of the requirements on the impl of `Gettable<Foo>` for `S | LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ^^^^^^^^^^^ ^^^^ - = note: required for the cast to the object type `dyn Gettable<Foo>` + = note: required for the cast from `S<Foo>` to the object type `dyn Gettable<Foo>` help: consider annotating `Foo` with `#[derive(Copy)]` | LL | #[derive(Copy)] diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index 727573a0be4ed..eab003a110782 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -2,16 +2,16 @@ error[E0277]: `Rc<usize>` cannot be sent between threads safely --> $DIR/kindck-nonsendable-1.rs:9:5 | LL | bar(move|| foo(x)); - | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]` + | ^^^ ------ within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15]` | | | `Rc<usize>` cannot be sent between threads safely | - = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc<usize>` + = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15]`, the trait `Send` is not implemented for `Rc<usize>` note: required because it's used within this closure --> $DIR/kindck-nonsendable-1.rs:9:9 | LL | bar(move|| foo(x)); - | ^^^^^^^^^^^^^ + | ^^^^^^ note: required by a bound in `bar` --> $DIR/kindck-nonsendable-1.rs:5:21 | diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr index 7dbcc15185501..7ba9657fcd6f1 100644 --- a/src/test/ui/layout/debug.stderr +++ b/src/test/ui/layout/debug.stderr @@ -84,7 +84,7 @@ error: layout_of(E) = Layout { --> $DIR/debug.rs:6:1 | LL | enum E { Foo, Bar(!, i32, i32) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(S) = Layout { fields: Arbitrary { @@ -128,7 +128,7 @@ error: layout_of(S) = Layout { --> $DIR/debug.rs:9:1 | LL | struct S { f1: i32, f2: (), f3: i32 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: layout_of(U) = Layout { fields: Union( @@ -150,7 +150,7 @@ error: layout_of(U) = Layout { --> $DIR/debug.rs:12:1 | LL | union U { f1: (i32, i32), f3: i32 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: layout_of(std::result::Result<i32, i32>) = Layout { fields: Arbitrary { @@ -279,7 +279,7 @@ error: layout_of(std::result::Result<i32, i32>) = Layout { --> $DIR/debug.rs:15:1 | LL | type Test = Result<i32, i32>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ error: layout_of(i32) = Layout { fields: Primitive, @@ -305,7 +305,7 @@ error: layout_of(i32) = Layout { --> $DIR/debug.rs:18:1 | LL | type T = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/layout/hexagon-enum.stderr b/src/test/ui/layout/hexagon-enum.stderr index ba919df771fca..f3123cb0ad22e 100644 --- a/src/test/ui/layout/hexagon-enum.stderr +++ b/src/test/ui/layout/hexagon-enum.stderr @@ -66,7 +66,7 @@ error: layout_of(A) = Layout { --> $DIR/hexagon-enum.rs:16:1 | LL | enum A { Apple } - | ^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(B) = Layout { fields: Arbitrary { @@ -136,7 +136,7 @@ error: layout_of(B) = Layout { --> $DIR/hexagon-enum.rs:20:1 | LL | enum B { Banana = 255, } - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(C) = Layout { fields: Arbitrary { @@ -206,7 +206,7 @@ error: layout_of(C) = Layout { --> $DIR/hexagon-enum.rs:24:1 | LL | enum C { Chaenomeles = 256, } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(P) = Layout { fields: Arbitrary { @@ -276,7 +276,7 @@ error: layout_of(P) = Layout { --> $DIR/hexagon-enum.rs:28:1 | LL | enum P { Peach = 0x1000_0000isize, } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(T) = Layout { fields: Arbitrary { @@ -346,7 +346,7 @@ error: layout_of(T) = Layout { --> $DIR/hexagon-enum.rs:34:1 | LL | enum T { Tangerine = TANGERINE as isize } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr b/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr index 6c97a09b0c666..e19216a99dbe5 100644 --- a/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr +++ b/src/test/ui/layout/homogeneous-aggr-zero-sized-c-struct.stderr @@ -2,13 +2,13 @@ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 byt --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:22:1 | LL | pub type TestMiddle = Middle; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/homogeneous-aggr-zero-sized-c-struct.rs:33:1 | LL | pub type TestFinal = Final; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr b/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr index 322948ff78399..17d639da0240a 100644 --- a/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr +++ b/src/test/ui/layout/homogeneous-aggr-zero-sized-repr-rust.stderr @@ -2,31 +2,31 @@ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 byt --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:53:1 | LL | pub type Test1 = BaseCase; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:57:1 | LL | pub type Test2 = WithPhantomData; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:61:1 | LL | pub type Test3 = WithEmptyRustStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:65:1 | LL | pub type Test4 = WithTransitivelyEmptyRustStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/homogeneous-aggr-zero-sized-repr-rust.rs:69:1 | LL | pub type Test5 = WithEmptyRustEnum; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 33dfa307c1d27..84d8bc799b93f 100644 --- a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -105,11 +105,8 @@ error: layout_of(MissingPayloadField) = Layout { } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1 | -LL | / pub enum MissingPayloadField { -LL | | Some(u8), -LL | | None -LL | | } - | |_^ +LL | pub enum MissingPayloadField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: layout_of(CommonPayloadField) = Layout { fields: Arbitrary { @@ -237,11 +234,8 @@ error: layout_of(CommonPayloadField) = Layout { } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1 | -LL | / pub enum CommonPayloadField { -LL | | A(u8), -LL | | B(u8), -LL | | } - | |_^ +LL | pub enum CommonPayloadField { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { fields: Arbitrary { @@ -366,11 +360,8 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1 | -LL | / pub enum CommonPayloadFieldIsMaybeUninit { -LL | | A(u8), -LL | | B(MaybeUninit<u8>), -LL | | } - | |_^ +LL | pub enum CommonPayloadFieldIsMaybeUninit { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: layout_of(NicheFirst) = Layout { fields: Arbitrary { @@ -513,12 +504,8 @@ error: layout_of(NicheFirst) = Layout { } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1 | -LL | / pub enum NicheFirst { -LL | | A(HasNiche, u8), -LL | | B, -LL | | C -LL | | } - | |_^ +LL | pub enum NicheFirst { + | ^^^^^^^^^^^^^^^^^^^ error: layout_of(NicheSecond) = Layout { fields: Arbitrary { @@ -661,12 +648,8 @@ error: layout_of(NicheSecond) = Layout { } --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1 | -LL | / pub enum NicheSecond { -LL | | A(u8, HasNiche), -LL | | B, -LL | | C, -LL | | } - | |_^ +LL | pub enum NicheSecond { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/layout/issue-96185-overaligned-enum.rs b/src/test/ui/layout/issue-96185-overaligned-enum.rs new file mode 100644 index 0000000000000..ae1e6b012c39b --- /dev/null +++ b/src/test/ui/layout/issue-96185-overaligned-enum.rs @@ -0,0 +1,19 @@ +// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +// This cannot use `Scalar` abi since there is padding. +#[rustc_layout(debug)] +#[repr(align(8))] +pub enum Aligned1 { //~ ERROR: layout_of + Zero = 0, + One = 1, +} + +// This should use `Scalar` abi. +#[rustc_layout(debug)] +#[repr(align(1))] +pub enum Aligned2 { //~ ERROR: layout_of + Zero = 0, + One = 1, +} diff --git a/src/test/ui/layout/issue-96185-overaligned-enum.stderr b/src/test/ui/layout/issue-96185-overaligned-enum.stderr new file mode 100644 index 0000000000000..8dc364fa7c9bd --- /dev/null +++ b/src/test/ui/layout/issue-96185-overaligned-enum.stderr @@ -0,0 +1,172 @@ +error: layout_of(Aligned1) = Layout { + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $PREF_ALIGN, + }, + size: Size(8 bytes), + }, + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 1, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $PREF_ALIGN, + }, + size: Size(8 bytes), + }, + ], + }, + abi: Aggregate { + sized: true, + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + align: AbiAndPrefAlign { + abi: Align(8 bytes), + pref: $PREF_ALIGN, + }, + size: Size(8 bytes), + } + --> $DIR/issue-96185-overaligned-enum.rs:8:1 + | +LL | pub enum Aligned1 { + | ^^^^^^^^^^^^^^^^^ + +error: layout_of(Aligned2) = Layout { + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 0, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $PREF_ALIGN, + }, + size: Size(1 bytes), + }, + Layout { + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + variants: Single { + index: 1, + }, + abi: Aggregate { + sized: true, + }, + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $PREF_ALIGN, + }, + size: Size(1 bytes), + }, + ], + }, + abi: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $PREF_ALIGN, + }, + size: Size(1 bytes), + } + --> $DIR/issue-96185-overaligned-enum.rs:16:1 + | +LL | pub enum Aligned2 { + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/layout/thumb-enum.stderr b/src/test/ui/layout/thumb-enum.stderr index 9db9ad5a78486..e6ed626d5f1aa 100644 --- a/src/test/ui/layout/thumb-enum.stderr +++ b/src/test/ui/layout/thumb-enum.stderr @@ -66,7 +66,7 @@ error: layout_of(A) = Layout { --> $DIR/thumb-enum.rs:16:1 | LL | enum A { Apple } - | ^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(B) = Layout { fields: Arbitrary { @@ -136,7 +136,7 @@ error: layout_of(B) = Layout { --> $DIR/thumb-enum.rs:20:1 | LL | enum B { Banana = 255, } - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(C) = Layout { fields: Arbitrary { @@ -206,7 +206,7 @@ error: layout_of(C) = Layout { --> $DIR/thumb-enum.rs:24:1 | LL | enum C { Chaenomeles = 256, } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(P) = Layout { fields: Arbitrary { @@ -276,7 +276,7 @@ error: layout_of(P) = Layout { --> $DIR/thumb-enum.rs:28:1 | LL | enum P { Peach = 0x1000_0000isize, } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: layout_of(T) = Layout { fields: Arbitrary { @@ -346,7 +346,7 @@ error: layout_of(T) = Layout { --> $DIR/thumb-enum.rs:34:1 | LL | enum T { Tangerine = TANGERINE as isize } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 4ca3f7a1aad94..73b32066fadcd 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -3,30 +3,80 @@ // test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same // size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes). -// run-pass +// check-pass +// compile-flags: --crate-type=lib +// only-x86 -#![feature(no_niche)] +#![feature(repr_simd)] -use std::cell::UnsafeCell; +use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; use std::num::NonZeroU32 as N32; +use std::sync::{Mutex, RwLock}; struct Wrapper<T>(T); #[repr(transparent)] struct Transparent<T>(T); -#[repr(no_niche)] -struct NoNiche<T>(T); +struct NoNiche<T>(UnsafeCell<T>); -fn main() { - assert_eq!(size_of::<Option<Wrapper<u32>>>(), 8); - assert_eq!(size_of::<Option<Wrapper<N32>>>(), 4); - assert_eq!(size_of::<Option<Transparent<u32>>>(), 8); - assert_eq!(size_of::<Option<Transparent<N32>>>(), 4); - assert_eq!(size_of::<Option<NoNiche<u32>>>(), 8); - assert_eq!(size_of::<Option<NoNiche<N32>>>(), 8); +struct Size<const S: usize>; - assert_eq!(size_of::<Option<UnsafeCell<u32>>>(), 8); - assert_eq!(size_of::<Option<UnsafeCell<N32>>>(), 8); +macro_rules! check_sizes { + (check_one_specific_size: $ty:ty, $size:expr) => { + const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; + }; + // Any tests run on `UnsafeCell` must be the same for `Cell` + (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => { + check_sizes!(Cell<$ty>: $size => $optioned_size); + check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size); + }; + ($ty:ty: $size:expr => $optioned_size:expr) => { + check_sizes!(@actual_check: $ty: $size => $optioned_size); + }; + // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish + // it from other branches and not accidentally match any. + (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => { + check_sizes!(check_one_specific_size: $ty, $size); + check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); + check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); + }; + // only check that there is no niche (size goes up when wrapped in an option), + // don't check actual sizes + ($ty:ty) => { + check_sizes!(check_no_niche_opt: true, $ty); + }; + (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => { + const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::<Option<$ty>>()); }; + }; } + +const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); + +check_sizes!(Wrapper<u32>: 4 => 8); +check_sizes!(Wrapper<N32>: 4 => 4); // (✓ niche opt) +check_sizes!(Transparent<u32>: 4 => 8); +check_sizes!(Transparent<N32>: 4 => 4); // (✓ niche opt) +check_sizes!(NoNiche<u32>: 4 => 8); +check_sizes!(NoNiche<N32>: 4 => 8); + +check_sizes!(UnsafeCell<u32>: 4 => 8); +check_sizes!(UnsafeCell<N32>: 4 => 8); + +check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); +check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); + +check_sizes!(RwLock<&()>); +check_sizes!(Mutex<&()>); + +check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3); +check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3); + +trait Trait {} +check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3); + +#[repr(simd)] +pub struct Vec4<T>([T; 4]); + +check_sizes!(UnsafeCell<Vec4<N32>>: 16 => 32); diff --git a/src/test/ui/layout/zero-sized-array-union.stderr b/src/test/ui/layout/zero-sized-array-union.stderr index 8faf8593294cc..de2b863e4caa5 100644 --- a/src/test/ui/layout/zero-sized-array-union.stderr +++ b/src/test/ui/layout/zero-sized-array-union.stderr @@ -2,25 +2,25 @@ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 byt --> $DIR/zero-sized-array-union.rs:59:1 | LL | type TestBaz1 = Baz1; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/zero-sized-array-union.rs:70:1 | LL | type TestBaz2 = Baz2; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/zero-sized-array-union.rs:81:1 | LL | type TestBaz3 = Baz3; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) --> $DIR/zero-sized-array-union.rs:92:1 | LL | type TestBaz4 = Baz4; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches.rs b/src/test/ui/lazy-type-alias-impl-trait/branches.rs index aa172f3f19b6b..95239e2e341c8 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches.rs +++ b/src/test/ui/lazy-type-alias-impl-trait/branches.rs @@ -7,8 +7,19 @@ fn foo(b: bool) -> Foo { vec![42_i32] } else { std::iter::empty().collect() - //~^ ERROR `Foo` cannot be built from an iterator over elements of type `_` } } +type Bar = impl std::fmt::Debug; + +fn bar(b: bool) -> Bar { + let x: Bar = if b { + vec![42_i32] + } else { + std::iter::empty().collect() + //~^ ERROR a value of type `Bar` cannot be built from an iterator over elements of type `_` + }; + x +} + fn main() {} diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches.stderr b/src/test/ui/lazy-type-alias-impl-trait/branches.stderr index c3902f34706bd..6b87da0c040d5 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches.stderr +++ b/src/test/ui/lazy-type-alias-impl-trait/branches.stderr @@ -1,10 +1,10 @@ -error[E0277]: a value of type `Foo` cannot be built from an iterator over elements of type `_` - --> $DIR/branches.rs:9:28 +error[E0277]: a value of type `Bar` cannot be built from an iterator over elements of type `_` + --> $DIR/branches.rs:19:28 | LL | std::iter::empty().collect() - | ^^^^^^^ value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>` + | ^^^^^^^ value of type `Bar` cannot be built from `std::iter::Iterator<Item=_>` | - = help: the trait `FromIterator<_>` is not implemented for `Foo` + = help: the trait `FromIterator<_>` is not implemented for `Bar` note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches2.rs b/src/test/ui/lazy-type-alias-impl-trait/branches2.rs index af605e4d8062d..04218f5643d1c 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/branches2.rs +++ b/src/test/ui/lazy-type-alias-impl-trait/branches2.rs @@ -1,6 +1,6 @@ #![feature(type_alias_impl_trait)] -// run-pass +// check-pass type Foo = impl std::iter::FromIterator<i32> + PartialEq<Vec<i32>> + std::fmt::Debug; diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches3.rs b/src/test/ui/lazy-type-alias-impl-trait/branches3.rs new file mode 100644 index 0000000000000..30c0af8a5dc97 --- /dev/null +++ b/src/test/ui/lazy-type-alias-impl-trait/branches3.rs @@ -0,0 +1,36 @@ +#![feature(type_alias_impl_trait)] + +type Foo = impl for<'a> FnOnce(&'a str) -> usize; +type Bar = impl FnOnce(&'static str) -> usize; + +fn foo() -> Foo { + if true { + |s| s.len() //~ ERROR type annotations needed + } else { + panic!() + } +} +fn bar() -> Bar { + if true { + |s| s.len() //~ ERROR type annotations needed + } else { + panic!() + } +} + +fn foo2() -> impl for<'a> FnOnce(&'a str) -> usize { + if true { + |s| s.len() //~ ERROR type annotations needed + } else { + panic!() + } +} +fn bar2() -> impl FnOnce(&'static str) -> usize { + if true { + |s| s.len() //~ ERROR type annotations needed + } else { + panic!() + } +} + +fn main() {} diff --git a/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr new file mode 100644 index 0000000000000..420104e526d9b --- /dev/null +++ b/src/test/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -0,0 +1,47 @@ +error[E0282]: type annotations needed + --> $DIR/branches3.rs:8:10 + | +LL | |s| s.len() + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | |s: _| s.len() + | +++ + +error[E0282]: type annotations needed + --> $DIR/branches3.rs:15:10 + | +LL | |s| s.len() + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | |s: _| s.len() + | +++ + +error[E0282]: type annotations needed + --> $DIR/branches3.rs:23:10 + | +LL | |s| s.len() + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | |s: _| s.len() + | +++ + +error[E0282]: type annotations needed + --> $DIR/branches3.rs:30:10 + | +LL | |s| s.len() + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | |s: _| s.len() + | +++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs b/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs index 1cc64ea17e79e..6b3d9ff4cdec8 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs +++ b/src/test/ui/lazy-type-alias-impl-trait/recursion2.rs @@ -1,5 +1,7 @@ #![feature(type_alias_impl_trait)] +// check-pass + type Foo = impl std::fmt::Debug; fn foo(b: bool) -> Foo { @@ -7,7 +9,7 @@ fn foo(b: bool) -> Foo { return vec![]; } let x: Vec<i32> = foo(false); - std::iter::empty().collect() //~ ERROR `Foo` cannot be built from an iterator + std::iter::empty().collect() } fn bar(b: bool) -> impl std::fmt::Debug { diff --git a/src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr b/src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr deleted file mode 100644 index 1f6201a8300c6..0000000000000 --- a/src/test/ui/lazy-type-alias-impl-trait/recursion2.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0277]: a value of type `Foo` cannot be built from an iterator over elements of type `_` - --> $DIR/recursion2.rs:10:24 - | -LL | std::iter::empty().collect() - | ^^^^^^^ value of type `Foo` cannot be built from `std::iter::Iterator<Item=_>` - | - = help: the trait `FromIterator<_>` is not implemented for `Foo` -note: required by a bound in `collect` - --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | -LL | fn collect<B: FromIterator<Self::Item>>(self) -> B - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr index fdec7e7f6a753..065787cab08ff 100644 --- a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr +++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37 | LL | let Some(n): &mut Option<i32> = &&Some(5i32) else { return }; - | ^^^^^^^^^^^^ types differ in mutability + | ---------------- ^^^^^^^^^^^^ types differ in mutability + | | + | expected due to this | = note: expected mutable reference `&mut Option<i32>` found reference `&&Option<i32>` @@ -11,7 +13,9 @@ error[E0308]: mismatched types --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37 | LL | let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return }; - | ^^^^^^^^^^^^^^^^ types differ in mutability + | ---------------- ^^^^^^^^^^^^^^^^ types differ in mutability + | | + | expected due to this | = note: expected mutable reference `&mut Option<i32>` found reference `&&mut Option<i32>` diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr index b3da412ec280e..3d647a4c05d86 100644 --- a/src/test/ui/let-else/let-else-check.stderr +++ b/src/test/ui/let-else/let-else-check.stderr @@ -1,8 +1,8 @@ error: unused variable: `x` - --> $DIR/let-else-check.rs:18:9 + --> $DIR/let-else-check.rs:14:13 | -LL | let x = 1; - | ^ help: if this is intentional, prefix it with an underscore: `_x` +LL | let x = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_x` | note: the lint level is defined here --> $DIR/let-else-check.rs:3:9 @@ -11,10 +11,10 @@ LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ error: unused variable: `x` - --> $DIR/let-else-check.rs:14:13 + --> $DIR/let-else-check.rs:18:9 | -LL | let x = 1; - | ^ help: if this is intentional, prefix it with an underscore: `_x` +LL | let x = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_x` error: aborting due to 2 previous errors diff --git a/src/test/ui/let-else/let-else-non-diverging.stderr b/src/test/ui/let-else/let-else-non-diverging.stderr index b961b16b6f6ef..05e45f689890d 100644 --- a/src/test/ui/let-else/let-else-non-diverging.stderr +++ b/src/test/ui/let-else/let-else-non-diverging.stderr @@ -1,8 +1,11 @@ error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:12:32 + --> $DIR/let-else-non-diverging.rs:4:32 | -LL | let Some(x) = Some(1) else { Some(2) }; - | ^^^^^^^^^^^ expected `!`, found enum `Option` +LL | let Some(x) = Some(1) else { + | ________________________________^ +LL | | Some(2) +LL | | }; + | |_____^ expected `!`, found enum `Option` | = note: expected type `!` found enum `Option<{integer}>` @@ -26,13 +29,10 @@ LL | | }; = help: ...or use `match` instead of `let...else` error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:4:32 + --> $DIR/let-else-non-diverging.rs:12:32 | -LL | let Some(x) = Some(1) else { - | ________________________________^ -LL | | Some(2) -LL | | }; - | |_____^ expected `!`, found enum `Option` +LL | let Some(x) = Some(1) else { Some(2) }; + | ^^^^^^^^^^^ expected `!`, found enum `Option` | = note: expected type `!` found enum `Option<{integer}>` diff --git a/src/test/ui/let-else/let-else-ref-bindings.stderr b/src/test/ui/let-else/let-else-ref-bindings.stderr index 650f4ec5e779f..56b9e073330a6 100644 --- a/src/test/ui/let-else/let-else-ref-bindings.stderr +++ b/src/test/ui/let-else/let-else-ref-bindings.stderr @@ -20,7 +20,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:24:34 | LL | let Some(a): Option<&[u8]> = some else { return }; - | ^^^^ expected `&[u8]`, found struct `Vec` + | ------------- ^^^^ expected `&[u8]`, found struct `Vec` + | | + | expected due to this | = note: expected enum `Option<&[u8]>` found enum `Option<Vec<u8>>` @@ -29,7 +31,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:27:34 | LL | let Some(a): Option<&[u8]> = &some else { return }; - | ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>` + | ------------- ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>` + | | + | expected due to this | = note: expected enum `Option<&[u8]>` found reference `&Option<Vec<u8>>` @@ -56,7 +60,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:52:38 | LL | let Some(a): Option<&mut [u8]> = some else { return }; - | ^^^^ expected `&mut [u8]`, found struct `Vec` + | ----------------- ^^^^ expected `&mut [u8]`, found struct `Vec` + | | + | expected due to this | = note: expected enum `Option<&mut [u8]>` found enum `Option<Vec<u8>>` @@ -65,7 +71,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:55:38 | LL | let Some(a): Option<&mut [u8]> = &mut some else { return }; - | ^^^^^^^^^ expected enum `Option`, found mutable reference + | ----------------- ^^^^^^^^^ expected enum `Option`, found mutable reference + | | + | expected due to this | = note: expected enum `Option<&mut [u8]>` found mutable reference `&mut Option<Vec<u8>>` diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs new file mode 100644 index 0000000000000..624c2ea37a70b --- /dev/null +++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs @@ -0,0 +1,25 @@ +// run-pass +#![feature(let_else)] + +use std::sync::atomic::{AtomicU8, Ordering}; + +static TRACKER: AtomicU8 = AtomicU8::new(0); + +#[derive(Default)] +struct Droppy { + inner: u32, +} + +impl Drop for Droppy { + fn drop(&mut self) { + TRACKER.store(1, Ordering::Release); + println!("I've been dropped"); + } +} + +fn main() { + assert_eq!(TRACKER.load(Ordering::Acquire), 0); + let 0 = Droppy::default().inner else { return }; + assert_eq!(TRACKER.load(Ordering::Acquire), 1); + println!("Should have dropped 👆"); +} diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr index 1e6a35ed479f6..3b2a062c1c254 100644 --- a/src/test/ui/lexical-scopes.stderr +++ b/src/test/ui/lexical-scopes.stderr @@ -7,6 +7,8 @@ LL | let t = T { i: 0 }; error[E0599]: no function or associated item named `f` found for type parameter `Foo` in the current scope --> $DIR/lexical-scopes.rs:10:10 | +LL | fn g<Foo>() { + | --- function or associated item `f` not found for this type parameter LL | Foo::f(); | ^ function or associated item not found in `Foo` diff --git a/src/test/ui/lifetimes/bare-trait-object-borrowck.rs b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs new file mode 100644 index 0000000000000..45f5e4ae129a1 --- /dev/null +++ b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs @@ -0,0 +1,24 @@ +#![allow(bare_trait_objects)] +// check-pass +pub struct FormatWith<'a, I, F> { + sep: &'a str, + /// FormatWith uses interior mutability because Display::fmt takes &self. + inner: RefCell<Option<(I, F)>>, +} + +use std::cell::RefCell; +use std::fmt; + +struct Layout; + +pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F> +where + I: Iterator, + F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result, +{ + FormatWith { sep: separator, inner: RefCell::new(Some((iter, f))) } +} + +fn main() { + let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i))); +} diff --git a/src/test/ui/lifetimes/bare-trait-object.rs b/src/test/ui/lifetimes/bare-trait-object.rs new file mode 100644 index 0000000000000..9eff618c734d5 --- /dev/null +++ b/src/test/ui/lifetimes/bare-trait-object.rs @@ -0,0 +1,25 @@ +// Verify that lifetime resolution correctly accounts for `Fn` bare trait objects. +// check-pass +#![allow(bare_trait_objects)] + +// This should work as: fn next_u32(fill_buf: &mut dyn FnMut(&mut [u8])) +fn next_u32(fill_buf: &mut FnMut(&mut [u8])) { + let mut buf: [u8; 4] = [0; 4]; + fill_buf(&mut buf); +} + +fn explicit(fill_buf: &mut dyn FnMut(&mut [u8])) { + let mut buf: [u8; 4] = [0; 4]; + fill_buf(&mut buf); +} + +fn main() { + let _: fn(&mut FnMut(&mut [u8])) = next_u32; + let _: &dyn Fn(&mut FnMut(&mut [u8])) = &next_u32; + let _: fn(&mut FnMut(&mut [u8])) = explicit; + let _: &dyn Fn(&mut FnMut(&mut [u8])) = &explicit; + let _: fn(&mut dyn FnMut(&mut [u8])) = next_u32; + let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &next_u32; + let _: fn(&mut dyn FnMut(&mut [u8])) = explicit; + let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &explicit; +} diff --git a/src/test/ui/lifetimes/issue-34979.stderr b/src/test/ui/lifetimes/issue-34979.stderr index 1b97f8d818a45..5832c4d173c10 100644 --- a/src/test/ui/lifetimes/issue-34979.stderr +++ b/src/test/ui/lifetimes/issue-34979.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo` --> $DIR/issue-34979.rs:6:13 | LL | &'a (): Foo, - | ^^^ cannot infer type for reference `&'a ()` + | ^^^ | = note: cannot satisfy `&'a (): Foo` diff --git a/src/test/ui/lifetimes/issue-79187-2.stderr b/src/test/ui/lifetimes/issue-79187-2.stderr index 6d8f2f5668321..9322e617176a1 100644 --- a/src/test/ui/lifetimes/issue-79187-2.stderr +++ b/src/test/ui/lifetimes/issue-79187-2.stderr @@ -37,7 +37,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187-2.rs:8:14 | LL | take_foo(|a| a); - | ^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/issue-79187-2.rs:5:21 | diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr index 1d89d4dac5ed3..3e75e7fed2cc1 100644 --- a/src/test/ui/lifetimes/issue-79187.stderr +++ b/src/test/ui/lifetimes/issue-79187.stderr @@ -10,7 +10,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187.rs:4:13 | LL | let f = |_| (); - | ^^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/issue-79187.rs:1:18 | diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index 33f6c498b6f35..affb4e8d04434 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -9,6 +9,28 @@ help: consider adding an explicit lifetime bound... LL | struct Foo<T: 'static> { | +++++++++ +error[E0309]: the parameter type `K` may not live long enough + --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 + | +LL | fn generic_in_parent<'a, L: X<&'a Nested<K>>>() { + | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl<K: 'a> Nested<K> { + | ++++ + +error[E0309]: the parameter type `M` may not live long enough + --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 + | +LL | fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() { + | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b + 'a>() { + | ++++ + error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 | @@ -40,28 +62,6 @@ help: consider adding an explicit lifetime bound... LL | fn baz<'a, L: 'a, M: X<&'a Nested<L>>>() { | ++++ -error[E0309]: the parameter type `K` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 - | -LL | fn generic_in_parent<'a, L: X<&'a Nested<K>>>() { - | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at - | -help: consider adding an explicit lifetime bound... - | -LL | impl<K: 'a> Nested<K> { - | ++++ - -error[E0309]: the parameter type `M` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 - | -LL | fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() { - | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at - | -help: consider adding an explicit lifetime bound... - | -LL | fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b + 'a>() { - | ++++ - error: aborting due to 6 previous errors Some errors have detailed explanations: E0309, E0310. diff --git a/src/test/ui/lifetimes/re-empty-in-error.stderr b/src/test/ui/lifetimes/re-empty-in-error.stderr index 3a5ab62ab96f6..72bb0782f4b4f 100644 --- a/src/test/ui/lifetimes/re-empty-in-error.stderr +++ b/src/test/ui/lifetimes/re-empty-in-error.stderr @@ -4,7 +4,7 @@ error: higher-ranked lifetime error LL | foo(&10); | ^^^^^^^^ | - = note: could not prove for<'b, 'r> &'b (): 'r + = note: could not prove `for<'b, 'r> &'b (): 'r` error: aborting due to previous error diff --git a/src/test/ui/limits/issue-55878.stderr b/src/test/ui/limits/issue-55878.stderr index 90411353f0825..1402d1387037e 100644 --- a/src/test/ui/limits/issue-55878.stderr +++ b/src/test/ui/limits/issue-55878.stderr @@ -23,3 +23,15 @@ LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: erroneous constant used + --> $DIR/issue-55878.rs:7:26 + | +LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/limits/issue-56762.stderr b/src/test/ui/limits/issue-56762.stderr index f26ef280b20b7..e6b9c67627893 100644 --- a/src/test/ui/limits/issue-56762.stderr +++ b/src/test/ui/limits/issue-56762.stderr @@ -2,13 +2,13 @@ error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the --> $DIR/issue-56762.rs:19:1 | LL | static MY_TOO_BIG_ARRAY_1: TooBigArray = TooBigArray::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: values of the type `[u8; 2305843009213693951]` are too big for the current architecture --> $DIR/issue-56762.rs:21:1 | LL | static MY_TOO_BIG_ARRAY_2: [u8; HUGE_SIZE] = [0x00; HUGE_SIZE]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr index dcb954a4bc0c1..06a070822630e 100644 --- a/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr +++ b/src/test/ui/linkage-attr/linkage-detect-extern-generated-name-collision.stderr @@ -2,7 +2,7 @@ error: symbol `collision` is already defined --> $DIR/auxiliary/def_colliding_external.rs:6:5 | LL | pub static collision: *const i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr index 7e395e67378f8..e0be1ac2117bd 100644 --- a/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr +++ b/src/test/ui/linkage-attr/linkage-detect-local-generated-name-collision.stderr @@ -2,7 +2,7 @@ error: symbol `collision` is already defined --> $DIR/linkage-detect-local-generated-name-collision.rs:10:9 | LL | pub static collision: *const i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr index a80b495f97fa3..5abbe745c6a21 100644 --- a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr +++ b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr @@ -2,7 +2,7 @@ error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute --> $DIR/auxiliary/def_illtyped_external.rs:5:1 | LL | pub static EXTERN: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/linkage-attr/linkage2.stderr b/src/test/ui/linkage-attr/linkage2.stderr index 6ffe07170ede7..a6ac0aad07787 100644 --- a/src/test/ui/linkage-attr/linkage2.stderr +++ b/src/test/ui/linkage-attr/linkage2.stderr @@ -2,7 +2,7 @@ error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute --> $DIR/linkage2.rs:12:5 | LL | static foo: i32; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/linkage-attr/linkage3.stderr b/src/test/ui/linkage-attr/linkage3.stderr index 0cbac28349d5a..f2579c6e850f7 100644 --- a/src/test/ui/linkage-attr/linkage3.stderr +++ b/src/test/ui/linkage-attr/linkage3.stderr @@ -2,7 +2,7 @@ error: invalid linkage specified --> $DIR/linkage3.rs:11:5 | LL | static foo: *const i32; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index 2ce4dd56eab0d..809e0602671fe 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -1,7 +1,6 @@ // check-pass // aux-build:external_extern_fn.rs #![crate_type = "lib"] -#![feature(no_niche)] #![warn(clashing_extern_declarations)] mod redeclared_different_signature { @@ -400,9 +399,8 @@ mod hidden_niche { #[repr(transparent)] struct Transparent { x: NonZeroUsize } - #[repr(no_niche)] #[repr(transparent)] - struct TransparentNoNiche { y: NonZeroUsize } + struct TransparentNoNiche { y: UnsafeCell<NonZeroUsize> } extern "C" { fn hidden_niche_transparent() -> Option<Transparent>; diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr index a856de322c8ca..4607f68499322 100644 --- a/src/test/ui/lint/clashing-extern-fn.stderr +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `clash` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:15:13 + --> $DIR/clashing-extern-fn.rs:14:13 | LL | fn clash(x: u8); | ---------------- `clash` previously declared here @@ -8,7 +8,7 @@ LL | fn clash(x: u64); | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | note: the lint level is defined here - --> $DIR/clashing-extern-fn.rs:5:9 + --> $DIR/clashing-extern-fn.rs:4:9 | LL | #![warn(clashing_extern_declarations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | #![warn(clashing_extern_declarations)] found `unsafe extern "C" fn(u64)` warning: `extern_link_name` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:53:9 + --> $DIR/clashing-extern-fn.rs:52:9 | LL | / #[link_name = "extern_link_name"] LL | | fn some_new_name(x: i16); @@ -29,7 +29,7 @@ LL | fn extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature - --> $DIR/clashing-extern-fn.rs:56:9 + --> $DIR/clashing-extern-fn.rs:55:9 | LL | fn some_other_new_name(x: i16); | ------------------------------- `some_other_new_name` previously declared here @@ -43,7 +43,7 @@ LL | | fn some_other_extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `other_both_names_different` redeclares `link_name_same` with a different signature - --> $DIR/clashing-extern-fn.rs:60:9 + --> $DIR/clashing-extern-fn.rs:59:9 | LL | / #[link_name = "link_name_same"] LL | | fn both_names_different(x: i16); @@ -58,7 +58,7 @@ LL | | fn other_both_names_different(x: u32); found `unsafe extern "C" fn(u32)` warning: `different_mod` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:73:9 + --> $DIR/clashing-extern-fn.rs:72:9 | LL | fn different_mod(x: u8); | ------------------------ `different_mod` previously declared here @@ -70,7 +70,7 @@ LL | fn different_mod(x: u64); found `unsafe extern "C" fn(u64)` warning: `variadic_decl` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:83:9 + --> $DIR/clashing-extern-fn.rs:82:9 | LL | fn variadic_decl(x: u8, ...); | ----------------------------- `variadic_decl` previously declared here @@ -82,7 +82,7 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:143:13 + --> $DIR/clashing-extern-fn.rs:142:13 | LL | fn weigh_banana(count: *const Banana) -> u64; | --------------------------------------------- `weigh_banana` previously declared here @@ -94,7 +94,7 @@ LL | fn weigh_banana(count: *const Banana) -> u64; found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:172:13 + --> $DIR/clashing-extern-fn.rs:171:13 | LL | fn draw_point(p: Point); | ------------------------ `draw_point` previously declared here @@ -106,7 +106,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:198:13 + --> $DIR/clashing-extern-fn.rs:197:13 | LL | fn origin() -> Point3; | ---------------------- `origin` previously declared here @@ -118,7 +118,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:221:13 + --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -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:239:13 + --> $DIR/clashing-extern-fn.rs:238: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:257:13 + --> $DIR/clashing-extern-fn.rs:256: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:259:13 + --> $DIR/clashing-extern-fn.rs:258: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:357:13 + --> $DIR/clashing-extern-fn.rs:356: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:359:13 + --> $DIR/clashing-extern-fn.rs:358: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:410:13 + --> $DIR/clashing-extern-fn.rs:408: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:414:13 + --> $DIR/clashing-extern-fn.rs:412: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:410:55 + --> $DIR/clashing-extern-fn.rs:408: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: enum has no representation hint warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:414:46 + --> $DIR/clashing-extern-fn.rs:412:46 | LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe diff --git a/src/test/ui/lint/dead-code/impl-trait.stderr b/src/test/ui/lint/dead-code/impl-trait.stderr index 9c47c1b53555f..e35e13a9ec6d6 100644 --- a/src/test/ui/lint/dead-code/impl-trait.stderr +++ b/src/test/ui/lint/dead-code/impl-trait.stderr @@ -1,8 +1,8 @@ error: type alias `Unused` is never used - --> $DIR/impl-trait.rs:12:1 + --> $DIR/impl-trait.rs:12:6 | LL | type Unused = (); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ | note: the lint level is defined here --> $DIR/impl-trait.rs:1:9 diff --git a/src/test/ui/lint/dead-code/issue-85255.stderr b/src/test/ui/lint/dead-code/issue-85255.stderr index 7ebbebb1abad7..3497b952fdd0b 100644 --- a/src/test/ui/lint/dead-code/issue-85255.stderr +++ b/src/test/ui/lint/dead-code/issue-85255.stderr @@ -4,9 +4,9 @@ warning: fields `a` and `b` are never read LL | struct Foo { | --- fields in this struct LL | a: i32, - | ^^^^^^ + | ^ LL | pub b: i32, - | ^^^^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/issue-85255.rs:4:9 @@ -14,6 +14,26 @@ note: the lint level is defined here LL | #![warn(dead_code)] | ^^^^^^^^^ +warning: fields `a` and `b` are never read + --> $DIR/issue-85255.rs:19:5 + | +LL | pub(crate) struct Foo1 { + | ---- fields in this struct +LL | a: i32, + | ^ +LL | pub b: i32, + | ^ + +warning: fields `a` and `b` are never read + --> $DIR/issue-85255.rs:31:5 + | +LL | pub(crate) struct Foo2 { + | ---- fields in this struct +LL | a: i32, + | ^ +LL | pub b: i32, + | ^ + warning: associated function `a` is never used --> $DIR/issue-85255.rs:14:8 | @@ -26,16 +46,6 @@ warning: associated function `b` is never used LL | pub fn b(&self) -> i32 { 6 } | ^ -warning: fields `a` and `b` are never read - --> $DIR/issue-85255.rs:19:5 - | -LL | pub(crate) struct Foo1 { - | ---- fields in this struct -LL | a: i32, - | ^^^^^^ -LL | pub b: i32, - | ^^^^^^^^^^ - warning: associated function `a` is never used --> $DIR/issue-85255.rs:26:8 | @@ -48,16 +58,6 @@ warning: associated function `b` is never used LL | pub fn b(&self) -> i32 { 6 } | ^ -warning: fields `a` and `b` are never read - --> $DIR/issue-85255.rs:31:5 - | -LL | pub(crate) struct Foo2 { - | ---- fields in this struct -LL | a: i32, - | ^^^^^^ -LL | pub b: i32, - | ^^^^^^^^^^ - warning: associated function `a` is never used --> $DIR/issue-85255.rs:38:8 | diff --git a/src/test/ui/lint/dead-code/lint-dead-code-1.stderr b/src/test/ui/lint/dead-code/lint-dead-code-1.stderr index 2eddc4ce21cd5..eb728b5b93055 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-1.stderr +++ b/src/test/ui/lint/dead-code/lint-dead-code-1.stderr @@ -1,8 +1,8 @@ error: static `priv_static` is never used - --> $DIR/lint-dead-code-1.rs:20:1 + --> $DIR/lint-dead-code-1.rs:20:8 | LL | static priv_static: isize = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-dead-code-1.rs:5:9 @@ -11,10 +11,10 @@ LL | #![deny(dead_code)] | ^^^^^^^^^ error: constant `priv_const` is never used - --> $DIR/lint-dead-code-1.rs:27:1 + --> $DIR/lint-dead-code-1.rs:27:7 | LL | const priv_const: isize = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: struct `PrivStruct` is never constructed --> $DIR/lint-dead-code-1.rs:35:8 diff --git a/src/test/ui/lint/dead-code/lint-dead-code-3.rs b/src/test/ui/lint/dead-code/lint-dead-code-3.rs index c3e56063dc3db..293fcdbc5ee7f 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-3.rs +++ b/src/test/ui/lint/dead-code/lint-dead-code-3.rs @@ -73,7 +73,18 @@ mod inner { fn f() {} } +fn anon_const() -> [(); { + fn blah() {} //~ ERROR: function `blah` is never used + 1 +}] { + [(); { + fn blah() {} //~ ERROR: function `blah` is never used + 1 + }] +} + pub fn foo() { let a: &dyn inner::Trait = &1_isize; a.f(); + anon_const(); } diff --git a/src/test/ui/lint/dead-code/lint-dead-code-3.stderr b/src/test/ui/lint/dead-code/lint-dead-code-3.stderr index af59c6fec1f8d..26fc13bae08a1 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-3.stderr +++ b/src/test/ui/lint/dead-code/lint-dead-code-3.stderr @@ -10,12 +10,6 @@ note: the lint level is defined here LL | #![deny(dead_code)] | ^^^^^^^^^ -error: associated function `foo` is never used - --> $DIR/lint-dead-code-3.rs:16:8 - | -LL | fn foo(&self) { - | ^^^ - error: function `bar` is never used --> $DIR/lint-dead-code-3.rs:21:4 | @@ -28,11 +22,29 @@ error: enum `c_void` is never used LL | enum c_void {} | ^^^^^^ +error: function `blah` is never used + --> $DIR/lint-dead-code-3.rs:77:8 + | +LL | fn blah() {} + | ^^^^ + +error: function `blah` is never used + --> $DIR/lint-dead-code-3.rs:81:12 + | +LL | fn blah() {} + | ^^^^ + +error: associated function `foo` is never used + --> $DIR/lint-dead-code-3.rs:16:8 + | +LL | fn foo(&self) { + | ^^^ + error: function `free` is never used - --> $DIR/lint-dead-code-3.rs:62:5 + --> $DIR/lint-dead-code-3.rs:62:8 | LL | fn free(p: *const c_void); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/lint/dead-code/lint-dead-code-4.stderr b/src/test/ui/lint/dead-code/lint-dead-code-4.stderr index dcd810b3e48e4..668c1dacf95a7 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-4.stderr +++ b/src/test/ui/lint/dead-code/lint-dead-code-4.stderr @@ -5,7 +5,7 @@ LL | struct Foo { | --- field in this struct LL | x: usize, LL | b: bool, - | ^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/lint-dead-code-4.rs:3:9 @@ -16,16 +16,12 @@ LL | #![deny(dead_code)] error: variants `X` and `Y` are never constructed --> $DIR/lint-dead-code-4.rs:15:5 | -LL | enum XYZ { - | --- variants in this enum -LL | X, - | ^ -LL | / Y { -LL | | a: String, -LL | | b: i32, -LL | | c: i32, -LL | | }, - | |_____^ +LL | enum XYZ { + | --- variants in this enum +LL | X, + | ^ +LL | Y { + | ^ error: enum `ABC` is never used --> $DIR/lint-dead-code-4.rs:24:6 @@ -36,13 +32,13 @@ LL | enum ABC { error: fields `b` and `c` are never read --> $DIR/lint-dead-code-4.rs:39:9 | -LL | enum IJK { - | --- fields in this enum -... +LL | J { + | - fields in this variant +LL | a: String, LL | b: i32, - | ^^^^^^ + | ^ LL | c: i32, - | ^^^^^^ + | ^ error: variants `I` and `K` are never constructed --> $DIR/lint-dead-code-4.rs:36:5 @@ -61,10 +57,10 @@ error: fields `x` and `c` are never read LL | struct Bar { | --- fields in this struct LL | x: usize, - | ^^^^^^^^ + | ^ LL | b: bool, LL | c: bool, - | ^^^^^^^ + | ^ error: aborting due to 6 previous errors diff --git a/src/test/ui/lint/dead-code/lint-dead-code-5.stderr b/src/test/ui/lint/dead-code/lint-dead-code-5.stderr index 037a9be22ad86..eaf43e4536104 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-5.stderr +++ b/src/test/ui/lint/dead-code/lint-dead-code-5.stderr @@ -20,9 +20,9 @@ LL | enum Enum2 { | ----- variants in this enum ... LL | Variant5 { _x: isize }, - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ LL | Variant6(isize), - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: enum `Enum3` is never used --> $DIR/lint-dead-code-5.rs:35:6 diff --git a/src/test/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr b/src/test/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr index 5cc8e06c09d4e..c0f1ed38f6de3 100644 --- a/src/test/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr +++ b/src/test/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr @@ -5,12 +5,12 @@ LL | struct Bar { | --- fields in this struct ... LL | d: usize, - | ^^^^^^^^ + | ^ ... LL | f: usize, - | ^^^^^^^^ + | ^ LL | g: usize, - | ^^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/multiple-dead-codes-in-the-same-struct.rs:1:9 @@ -25,10 +25,10 @@ LL | struct Bar { | --- fields in this struct ... LL | c: usize, - | ^^^^^^^^ + | ^ ... LL | e: usize, - | ^^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/multiple-dead-codes-in-the-same-struct.rs:8:12 @@ -43,7 +43,7 @@ LL | struct Bar { | --- field in this struct ... LL | b: usize, - | ^^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/multiple-dead-codes-in-the-same-struct.rs:6:14 diff --git a/src/test/ui/lint/dead-code/type-alias.stderr b/src/test/ui/lint/dead-code/type-alias.stderr index 80c6ba962b806..446447d974a86 100644 --- a/src/test/ui/lint/dead-code/type-alias.stderr +++ b/src/test/ui/lint/dead-code/type-alias.stderr @@ -1,8 +1,8 @@ error: type alias `Unused` is never used - --> $DIR/type-alias.rs:4:1 + --> $DIR/type-alias.rs:4:6 | LL | type Unused = u8; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^ | note: the lint level is defined here --> $DIR/type-alias.rs:1:9 diff --git a/src/test/ui/lint/dead-code/unused-struct-variant.stderr b/src/test/ui/lint/dead-code/unused-struct-variant.stderr index b08402b671b37..d26dd3aff9547 100644 --- a/src/test/ui/lint/dead-code/unused-struct-variant.stderr +++ b/src/test/ui/lint/dead-code/unused-struct-variant.stderr @@ -5,7 +5,7 @@ LL | enum E { | - variant in this enum LL | Foo(F), LL | Bar(B), - | ^^^^^^ + | ^^^ | note: the lint level is defined here --> $DIR/unused-struct-variant.rs:1:9 diff --git a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr index af6308f0d1b4f..915b3b86fe80e 100644 --- a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/allowed-cli-deny-by-default-lint.rs:6:16 | LL | const C: i32 = 1 / 0; - | ---------------^^^^^- - | | - | attempt to divide `1_i32` by zero + | ------------ ^^^^^ attempt to divide `1_i32` by zero | = note: requested on the command line with `--force-warn const-err` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const C: i32 = 1 / 0; warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/allowed-cli-deny-by-default-lint.rs:6:16 + | +LL | const C: i32 = 1 / 0; + | ------------ ^^^^^ attempt to divide `1_i32` by zero + | + = note: requested on the command line with `--force-warn const-err` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr index 05656afd22d88..3b36d1d022719 100644 --- a/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/allowed-deny-by-default-lint.rs:7:16 | LL | const C: i32 = 1 / 0; - | ---------------^^^^^- - | | - | attempt to divide `1_i32` by zero + | ------------ ^^^^^ attempt to divide `1_i32` by zero | = note: requested on the command line with `--force-warn const-err` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const C: i32 = 1 / 0; warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/allowed-deny-by-default-lint.rs:7:16 + | +LL | const C: i32 = 1 / 0; + | ------------ ^^^^^ attempt to divide `1_i32` by zero + | + = note: requested on the command line with `--force-warn const-err` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/lint/force-warn/deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/deny-by-default-lint.stderr index ef295f99e649c..a2e5baa8b9d42 100644 --- a/src/test/ui/lint/force-warn/deny-by-default-lint.stderr +++ b/src/test/ui/lint/force-warn/deny-by-default-lint.stderr @@ -2,9 +2,7 @@ warning: any use of this value will cause an error --> $DIR/deny-by-default-lint.rs:5:16 | LL | const C: i32 = 1 / 0; - | ---------------^^^^^- - | | - | attempt to divide `1_i32` by zero + | ------------ ^^^^^ attempt to divide `1_i32` by zero | = note: requested on the command line with `--force-warn const-err` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,3 +10,14 @@ LL | const C: i32 = 1 / 0; warning: 1 warning emitted +Future incompatibility report: Future breakage diagnostic: +warning: any use of this value will cause an error + --> $DIR/deny-by-default-lint.rs:5:16 + | +LL | const C: i32 = 1 / 0; + | ------------ ^^^^^ attempt to divide `1_i32` by zero + | + = note: requested on the command line with `--force-warn const-err` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> + diff --git a/src/test/ui/lint/issue-14309.stderr b/src/test/ui/lint/issue-14309.stderr index 799991f7ee4ba..a9538b5e3a49e 100644 --- a/src/test/ui/lint/issue-14309.stderr +++ b/src/test/ui/lint/issue-14309.stderr @@ -14,10 +14,8 @@ LL | #![deny(improper_ctypes)] note: the type is defined here --> $DIR/issue-14309.rs:4:1 | -LL | / struct A { -LL | | x: i32 -LL | | } - | |_^ +LL | struct A { + | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:31:15 @@ -30,10 +28,8 @@ LL | fn bar(x: B); note: the type is defined here --> $DIR/issue-14309.rs:4:1 | -LL | / struct A { -LL | | x: i32 -LL | | } - | |_^ +LL | struct A { + | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:33:15 @@ -46,10 +42,8 @@ LL | fn qux(x: A2); note: the type is defined here --> $DIR/issue-14309.rs:4:1 | -LL | / struct A { -LL | | x: i32 -LL | | } - | |_^ +LL | struct A { + | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:34:16 @@ -62,10 +56,8 @@ LL | fn quux(x: B2); note: the type is defined here --> $DIR/issue-14309.rs:4:1 | -LL | / struct A { -LL | | x: i32 -LL | | } - | |_^ +LL | struct A { + | ^^^^^^^^ error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:36:16 @@ -78,10 +70,8 @@ LL | fn fred(x: D); note: the type is defined here --> $DIR/issue-14309.rs:4:1 | -LL | / struct A { -LL | | x: i32 -LL | | } - | |_^ +LL | struct A { + | ^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/lint/issue-17718-const-naming.stderr b/src/test/ui/lint/issue-17718-const-naming.stderr index 4c97f6d63d4b6..7d2aadd5f8081 100644 --- a/src/test/ui/lint/issue-17718-const-naming.stderr +++ b/src/test/ui/lint/issue-17718-const-naming.stderr @@ -1,8 +1,8 @@ error: constant `foo` is never used - --> $DIR/issue-17718-const-naming.rs:4:1 + --> $DIR/issue-17718-const-naming.rs:4:7 | LL | const foo: isize = 3; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^ | note: the lint level is defined here --> $DIR/issue-17718-const-naming.rs:2:9 diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index 540e076c7e4c6..94d876423e749 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -10,7 +10,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:26:1 | LL | const ARRAY: [u8; 1] = [25]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item --> $DIR/lint-const-item-mutation.rs:38:5 @@ -23,7 +23,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item --> $DIR/lint-const-item-mutation.rs:39:5 @@ -36,7 +36,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item --> $DIR/lint-const-item-mutation.rs:40:5 @@ -55,7 +55,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item --> $DIR/lint-const-item-mutation.rs:41:5 @@ -69,7 +69,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item --> $DIR/lint-const-item-mutation.rs:42:5 @@ -83,7 +83,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item --> $DIR/lint-const-item-mutation.rs:54:5 @@ -96,7 +96,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:30:1 | LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item --> $DIR/lint-const-item-mutation.rs:55:5 @@ -115,7 +115,7 @@ note: `const` item defined here --> $DIR/lint-const-item-mutation.rs:31:1 | LL | const VEC: Vec<i32> = Vec::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ warning: 8 warnings emitted diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index 1601bd9d62927..de532f69ac0a5 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -14,10 +14,8 @@ LL | #![deny(improper_ctypes)] note: the type is defined here --> $DIR/lint-ctypes-enum.rs:9:1 | -LL | / enum U { -LL | | A, -LL | | } - | |_^ +LL | enum U { + | ^^^^^^ error: `extern` block uses type `B`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:61:13 @@ -30,11 +28,8 @@ LL | fn bf(x: B); note: the type is defined here --> $DIR/lint-ctypes-enum.rs:12:1 | -LL | / enum B { -LL | | C, -LL | | D, -LL | | } - | |_^ +LL | enum B { + | ^^^^^^ error: `extern` block uses type `T`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:62:13 @@ -47,12 +42,8 @@ LL | fn tf(x: T); note: the type is defined here --> $DIR/lint-ctypes-enum.rs:16:1 | -LL | / enum T { -LL | | E, -LL | | F, -LL | | G, -LL | | } - | |_^ +LL | enum T { + | ^^^^^^ error: `extern` block uses type `u128`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:74:23 diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr index 740075ca7dfff..6f8d76411aaeb 100644 --- a/src/test/ui/lint/lint-ctypes-fn.stderr +++ b/src/test/ui/lint/lint-ctypes-fn.stderr @@ -100,7 +100,7 @@ note: the type is defined here --> $DIR/lint-ctypes-fn.rs:28:1 | LL | pub struct ZeroSize; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:110:40 @@ -113,7 +113,7 @@ note: the type is defined here --> $DIR/lint-ctypes-fn.rs:63:1 | LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:113:51 diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index 342b6bfc6f87a..bfec40e195535 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -15,7 +15,7 @@ note: the type is defined here --> $DIR/lint-ctypes.rs:26:1 | LL | pub struct Foo; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: `extern` block uses type `Foo`, which is not FFI-safe --> $DIR/lint-ctypes.rs:49:28 @@ -29,7 +29,7 @@ note: the type is defined here --> $DIR/lint-ctypes.rs:26:1 | LL | pub struct Foo; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error: `extern` block uses type `((),)`, which is not FFI-safe --> $DIR/lint-ctypes.rs:51:25 @@ -139,7 +139,7 @@ note: the type is defined here --> $DIR/lint-ctypes.rs:22:1 | LL | pub struct ZeroSize; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe --> $DIR/lint-ctypes.rs:64:33 @@ -152,7 +152,7 @@ note: the type is defined here --> $DIR/lint-ctypes.rs:45:1 | LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe --> $DIR/lint-ctypes.rs:67:12 diff --git a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.rs b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.rs index c79c1daf77410..0e0d604ae046d 100644 --- a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.rs +++ b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.rs @@ -20,43 +20,43 @@ fn main() { // AcqRel is always forbidden as a failure ordering let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` // Release is always forbidden as a failure ordering let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release); - //~^ ERROR compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel` // Release success order forbids failure order of Acquire or SeqCst let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire); - //~^ ERROR compare_exchange_weak's failure ordering may not be stronger + //~^ ERROR `compare_exchange_weak`'s success ordering must be at least as strong as let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst); - //~^ ERROR compare_exchange_weak's failure ordering may not be stronger + //~^ ERROR `compare_exchange_weak`'s success ordering must be at least as strong as // Relaxed success order also forbids failure order of Acquire or SeqCst let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst); - //~^ ERROR compare_exchange_weak's failure ordering may not be stronger + //~^ ERROR `compare_exchange_weak`'s success ordering must be at least as strong as let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire); - //~^ ERROR compare_exchange_weak's failure ordering may not be stronger + //~^ ERROR `compare_exchange_weak`'s success ordering must be at least as strong as // Acquire/AcqRel forbids failure order of SeqCst let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst); - //~^ ERROR compare_exchange_weak's failure ordering may not be stronger + //~^ ERROR `compare_exchange_weak`'s success ordering must be at least as strong as let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst); - //~^ ERROR compare_exchange_weak's failure ordering may not be stronger + //~^ ERROR `compare_exchange_weak`'s success ordering must be at least as strong as } diff --git a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.stderr b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.stderr index 13350ab0b9c02..d5e53418b6fb8 100644 --- a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.stderr +++ b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange-weak.stderr @@ -1,131 +1,137 @@ -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:22:67 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Relaxed, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | = note: `#[deny(invalid_atomic_ordering)]` on by default - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:24:67 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:26:67 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:28:66 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:30:66 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::SeqCst, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:34:67 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:36:67 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Acquire, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:38:67 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Release, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:40:66 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::AcqRel, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange_weak`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange_weak` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:42:66 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::SeqCst, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release` - --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:46:67 +error: `compare_exchange_weak`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:46:48 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::Acquire); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ----------------- `Acquire` failure ordering + | | + | `Release` success ordering + | help: consider using `AcqRel` success ordering instead -error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Release` - --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:48:67 +error: `compare_exchange_weak`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:48:48 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Release, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Release` success ordering + | help: consider using `SeqCst` success ordering instead -error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed` - --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:52:67 +error: `compare_exchange_weak`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:52:48 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Relaxed` success ordering + | help: consider using `SeqCst` success ordering instead -error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Relaxed` - --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:54:67 +error: `compare_exchange_weak`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:54:48 | LL | let _ = x.compare_exchange_weak(ptr, ptr2, Ordering::Relaxed, Ordering::Acquire); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ----------------- `Acquire` failure ordering + | | + | `Relaxed` success ordering + | help: consider using `Acquire` success ordering instead -error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `Acquire` - --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:58:67 +error: `compare_exchange_weak`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:58:48 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::Acquire, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Acquire` success ordering + | help: consider using `SeqCst` success ordering instead -error: compare_exchange_weak's failure ordering may not be stronger than the success ordering of `AcqRel` - --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:60:66 +error: `compare_exchange_weak`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange-weak.rs:60:48 | LL | let _ = x.compare_exchange_weak(ptr2, ptr, Ordering::AcqRel, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + | ^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `AcqRel` success ordering + | help: consider using `SeqCst` success ordering instead error: aborting due to 16 previous errors diff --git a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.rs b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.rs index 8ef3a400cf040..da98d854262a5 100644 --- a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.rs +++ b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.rs @@ -18,43 +18,43 @@ fn main() { // AcqRel is always forbidden as a failure ordering let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` // Release is always forbidden as a failure ordering let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release); - //~^ ERROR compare_exchange's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `compare_exchange`'s failure ordering may not be `Release` or `AcqRel` // Release success order forbids failure order of Acquire or SeqCst let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire); - //~^ ERROR compare_exchange's failure ordering may not be stronger + //~^ ERROR `compare_exchange`'s success ordering must be at least as strong as let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst); - //~^ ERROR compare_exchange's failure ordering may not be stronger + //~^ ERROR `compare_exchange`'s success ordering must be at least as strong as // Relaxed success order also forbids failure order of Acquire or SeqCst let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst); - //~^ ERROR compare_exchange's failure ordering may not be stronger + //~^ ERROR `compare_exchange`'s success ordering must be at least as strong as let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire); - //~^ ERROR compare_exchange's failure ordering may not be stronger + //~^ ERROR `compare_exchange`'s success ordering must be at least as strong as // Acquire/AcqRel forbids failure order of SeqCst let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); - //~^ ERROR compare_exchange's failure ordering may not be stronger + //~^ ERROR `compare_exchange`'s success ordering must be at least as strong as let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); - //~^ ERROR compare_exchange's failure ordering may not be stronger + //~^ ERROR `compare_exchange`'s success ordering must be at least as strong as } diff --git a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.stderr b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.stderr index daedfec743093..41121a20dee99 100644 --- a/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.stderr +++ b/src/test/ui/lint/lint-invalid-atomic-ordering-exchange.stderr @@ -1,131 +1,137 @@ -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:20:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | = note: `#[deny(invalid_atomic_ordering)]` on by default - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:22:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:24:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:26:56 | LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:28:56 | LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::AcqRel); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:32:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:34:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:36:57 | LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:38:56 | LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be `Release` or `AcqRel` +error: `compare_exchange`'s failure ordering may not be `Release` or `AcqRel`, since a failed `compare_exchange` does not result in a write --> $DIR/lint-invalid-atomic-ordering-exchange.rs:40:56 | LL | let _ = x.compare_exchange(0, 0, Ordering::SeqCst, Ordering::Release); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release` - --> $DIR/lint-invalid-atomic-ordering-exchange.rs:44:57 +error: `compare_exchange`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange.rs:44:38 | LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::Acquire); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ----------------- `Acquire` failure ordering + | | + | `Release` success ordering + | help: consider using `AcqRel` success ordering instead -error: compare_exchange's failure ordering may not be stronger than the success ordering of `Release` - --> $DIR/lint-invalid-atomic-ordering-exchange.rs:46:57 +error: `compare_exchange`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange.rs:46:38 | LL | let _ = x.compare_exchange(0, 0, Ordering::Release, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Release` success ordering + | help: consider using `SeqCst` success ordering instead -error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed` - --> $DIR/lint-invalid-atomic-ordering-exchange.rs:50:57 +error: `compare_exchange`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange.rs:50:38 | LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Relaxed` success ordering + | help: consider using `SeqCst` success ordering instead -error: compare_exchange's failure ordering may not be stronger than the success ordering of `Relaxed` - --> $DIR/lint-invalid-atomic-ordering-exchange.rs:52:57 +error: `compare_exchange`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange.rs:52:38 | LL | let _ = x.compare_exchange(0, 0, Ordering::Relaxed, Ordering::Acquire); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ----------------- `Acquire` failure ordering + | | + | `Relaxed` success ordering + | help: consider using `Acquire` success ordering instead -error: compare_exchange's failure ordering may not be stronger than the success ordering of `Acquire` - --> $DIR/lint-invalid-atomic-ordering-exchange.rs:56:57 +error: `compare_exchange`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange.rs:56:38 | LL | let _ = x.compare_exchange(0, 0, Ordering::Acquire, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Acquire` success ordering + | help: consider using `SeqCst` success ordering instead -error: compare_exchange's failure ordering may not be stronger than the success ordering of `AcqRel` - --> $DIR/lint-invalid-atomic-ordering-exchange.rs:58:56 +error: `compare_exchange`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-exchange.rs:58:38 | LL | let _ = x.compare_exchange(0, 0, Ordering::AcqRel, Ordering::SeqCst); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + | ^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `AcqRel` success ordering + | help: consider using `SeqCst` success ordering instead error: aborting due to 16 previous errors diff --git a/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs b/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs index 938ca0359f845..73eda182aa879 100644 --- a/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs +++ b/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.rs @@ -18,43 +18,43 @@ fn main() { // AcqRel is always forbidden as a failure ordering let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` // Release is always forbidden as a failure ordering let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be `Release` or `AcqRel` + //~^ ERROR `fetch_update`'s failure ordering may not be `Release` or `AcqRel` // Release success order forbids failure order of Acquire or SeqCst let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be stronger + //~^ ERROR `fetch_update`'s success ordering must be at least as strong as let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be stronger + //~^ ERROR `fetch_update`'s success ordering must be at least as strong as // Relaxed success order also forbids failure order of Acquire or SeqCst let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be stronger + //~^ ERROR `fetch_update`'s success ordering must be at least as strong as let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be stronger + //~^ ERROR `fetch_update`'s success ordering must be at least as strong as // Acquire/AcqRel forbids failure order of SeqCst let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be stronger + //~^ ERROR `fetch_update`'s success ordering must be at least as strong as let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); - //~^ ERROR fetch_update's failure ordering may not be stronger + //~^ ERROR `fetch_update`'s success ordering must be at least as strong as } diff --git a/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr b/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr index dabc1da7e55c4..7bea56d57fbab 100644 --- a/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr +++ b/src/test/ui/lint/lint-invalid-atomic-ordering-fetch-update.stderr @@ -1,131 +1,137 @@ -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:20:47 | LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | = note: `#[deny(invalid_atomic_ordering)]` on by default - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:22:47 | LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:24:47 | LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:26:46 | LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:28:46 | LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:32:47 | LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:34:47 | LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:36:47 | LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering mode `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:38:46 | LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be `Release` or `AcqRel` +error: `fetch_update`'s failure ordering may not be `Release` or `AcqRel`, since a failed `fetch_update` does not result in a write --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:40:46 | LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ invalid failure ordering | - = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead + = help: consider using `Acquire` or `Relaxed` failure ordering instead -error: fetch_update's failure ordering may not be stronger than the success ordering of `Release` - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:44:47 +error: `fetch_update`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:44:28 | LL | let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ----------------- `Acquire` failure ordering + | | + | `Release` success ordering + | help: consider using `AcqRel` success ordering instead -error: fetch_update's failure ordering may not be stronger than the success ordering of `Release` - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:46:47 +error: `fetch_update`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:46:28 | LL | let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Release` success ordering + | help: consider using `SeqCst` success ordering instead -error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed` - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:50:47 +error: `fetch_update`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:50:28 | LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Relaxed` success ordering + | help: consider using `SeqCst` success ordering instead -error: fetch_update's failure ordering may not be stronger than the success ordering of `Relaxed` - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:52:47 +error: `fetch_update`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:52:28 | LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider using ordering mode `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ----------------- `Acquire` failure ordering + | | + | `Relaxed` success ordering + | help: consider using `Acquire` success ordering instead -error: fetch_update's failure ordering may not be stronger than the success ordering of `Acquire` - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:56:47 +error: `fetch_update`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:56:28 | LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + | ^^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `Acquire` success ordering + | help: consider using `SeqCst` success ordering instead -error: fetch_update's failure ordering may not be stronger than the success ordering of `AcqRel` - --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:58:46 +error: `fetch_update`'s success ordering must be at least as strong as its failure ordering + --> $DIR/lint-invalid-atomic-ordering-fetch-update.rs:58:28 | LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1)); - | ^^^^^^^^^^^^^^^^ - | - = help: consider using ordering modes `Acquire` or `Relaxed` instead + | ^^^^^^^^^^^^^^^^ ---------------- `SeqCst` failure ordering + | | + | `AcqRel` success ordering + | help: consider using `SeqCst` success ordering instead error: aborting due to 16 previous errors diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index 56f8fc10e8623..d68472d4b6602 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -2,7 +2,7 @@ error: missing documentation for a type alias --> $DIR/lint-missing-doc.rs:11:1 | LL | pub type PubTypedef = String; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-missing-doc.rs:3:9 @@ -56,13 +56,13 @@ error: missing documentation for an associated type --> $DIR/lint-missing-doc.rs:64:5 | LL | type AssociatedType; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type --> $DIR/lint-missing-doc.rs:65:5 | LL | type AssociatedTypeDef = Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated function --> $DIR/lint-missing-doc.rs:81:5 @@ -92,13 +92,13 @@ error: missing documentation for a constant --> $DIR/lint-missing-doc.rs:151:1 | LL | pub const FOO4: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static --> $DIR/lint-missing-doc.rs:161:1 | LL | pub static BAR4: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function --> $DIR/lint-missing-doc.rs:167:5 @@ -122,19 +122,19 @@ error: missing documentation for a function --> $DIR/lint-missing-doc.rs:189:5 | LL | pub fn extern_fn_undocumented(f: f32) -> f32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static --> $DIR/lint-missing-doc.rs:194:5 | LL | pub static EXTERN_STATIC_UNDOCUMENTED: u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a foreign type --> $DIR/lint-missing-doc.rs:199:5 | LL | pub type ExternTyUndocumented; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 22 previous errors diff --git a/src/test/ui/lint/lint-stability.rs b/src/test/ui/lint/lint-stability.rs index 464b32c5f43ed..d0f0e9f807123 100644 --- a/src/test/ui/lint/lint-stability.rs +++ b/src/test/ui/lint/lint-stability.rs @@ -191,11 +191,11 @@ mod inheritance { stable_mod::unstable(); //~ ERROR use of unstable library feature stable_mod::stable(); - unstable_mod::deprecated(); + unstable_mod::deprecated(); //~ ERROR use of unstable library feature unstable_mod::unstable(); //~ ERROR use of unstable library feature let _ = Unstable::UnstableVariant; //~ ERROR use of unstable library feature - let _ = Unstable::StableVariant; + let _ = Unstable::StableVariant; //~ ERROR use of unstable library feature let x: usize = 0; x.stable(); diff --git a/src/test/ui/lint/lint-stability.stderr b/src/test/ui/lint/lint-stability.stderr index 167140ef92b46..bd1a57dc4cc50 100644 --- a/src/test/ui/lint/lint-stability.stderr +++ b/src/test/ui/lint/lint-stability.stderr @@ -294,6 +294,14 @@ LL | stable_mod::unstable(); | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/lint-stability.rs:194:9 + | +LL | unstable_mod::deprecated(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:195:9 | @@ -310,6 +318,14 @@ LL | let _ = Unstable::UnstableVariant; | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/lint-stability.rs:198:17 + | +LL | let _ = Unstable::StableVariant; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/lint-stability.rs:88:48 | @@ -326,6 +342,6 @@ LL | TypeUnstable = u8, | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable -error: aborting due to 41 previous errors +error: aborting due to 43 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/lint/recommend-literal.rs b/src/test/ui/lint/recommend-literal.rs index f60d3d10dce47..453cbf28569e9 100644 --- a/src/test/ui/lint/recommend-literal.rs +++ b/src/test/ui/lint/recommend-literal.rs @@ -7,6 +7,13 @@ fn main() { let y: long = 74802374902374923; //~^ ERROR cannot find type `long` in this scope //~| HELP perhaps you intended to use this type + let v1: Boolean = true; + //~^ ERROR: cannot find type `Boolean` in this scope [E0412] + //~| HELP perhaps you intended to use this type + let v2: Bool = true; + //~^ ERROR: cannot find type `Bool` in this scope [E0412] + //~| HELP a builtin type with a similar name exists + //~| HELP perhaps you intended to use this type } fn z(a: boolean) { diff --git a/src/test/ui/lint/recommend-literal.stderr b/src/test/ui/lint/recommend-literal.stderr index 0ebcfb40dc3b8..424ecadd4b8cc 100644 --- a/src/test/ui/lint/recommend-literal.stderr +++ b/src/test/ui/lint/recommend-literal.stderr @@ -16,8 +16,32 @@ LL | let y: long = 74802374902374923; | not found in this scope | help: perhaps you intended to use this type: `i64` +error[E0412]: cannot find type `Boolean` in this scope + --> $DIR/recommend-literal.rs:10:13 + | +LL | let v1: Boolean = true; + | ^^^^^^^ + | | + | not found in this scope + | help: perhaps you intended to use this type: `bool` + +error[E0412]: cannot find type `Bool` in this scope + --> $DIR/recommend-literal.rs:13:13 + | +LL | let v2: Bool = true; + | ^^^^ + | +help: a builtin type with a similar name exists + | +LL | let v2: bool = true; + | ~~~~ +help: perhaps you intended to use this type + | +LL | let v2: bool = true; + | ~~~~ + error[E0412]: cannot find type `boolean` in this scope - --> $DIR/recommend-literal.rs:12:9 + --> $DIR/recommend-literal.rs:19:9 | LL | fn z(a: boolean) { | ^^^^^^^ @@ -26,7 +50,7 @@ LL | fn z(a: boolean) { | help: perhaps you intended to use this type: `bool` error[E0412]: cannot find type `byte` in this scope - --> $DIR/recommend-literal.rs:17:11 + --> $DIR/recommend-literal.rs:24:11 | LL | fn a() -> byte { | ^^^^ @@ -35,7 +59,7 @@ LL | fn a() -> byte { | help: perhaps you intended to use this type: `u8` error[E0412]: cannot find type `float` in this scope - --> $DIR/recommend-literal.rs:24:12 + --> $DIR/recommend-literal.rs:31:12 | LL | width: float, | ^^^^^ @@ -44,7 +68,7 @@ LL | width: float, | help: perhaps you intended to use this type: `f32` error[E0412]: cannot find type `int` in this scope - --> $DIR/recommend-literal.rs:27:19 + --> $DIR/recommend-literal.rs:34:19 | LL | depth: Option<int>, | ^^^ not found in this scope @@ -59,7 +83,7 @@ LL | struct Data<int> { | +++++ error[E0412]: cannot find type `short` in this scope - --> $DIR/recommend-literal.rs:33:16 + --> $DIR/recommend-literal.rs:40:16 | LL | impl Stuff for short {} | ^^^^^ @@ -67,6 +91,6 @@ LL | impl Stuff for short {} | not found in this scope | help: perhaps you intended to use this type: `i16` -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/lint/trivial_casts.stderr b/src/test/ui/lint/trivial_casts.stderr index 141703460ba0e..8a216360f4e3b 100644 --- a/src/test/ui/lint/trivial_casts.stderr +++ b/src/test/ui/lint/trivial_casts.stderr @@ -128,7 +128,7 @@ LL | let _ = &baz as &dyn Fn(i32); | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn Fn(i32)` +error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:22]` as `&dyn Fn(i32)` --> $DIR/trivial_casts.rs:73:13 | LL | let _ = &x as &dyn Fn(i32); diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/uninitialized-zeroed.stderr index b6a66f0a95ad1..88121a1836da4 100644 --- a/src/test/ui/lint/uninitialized-zeroed.stderr +++ b/src/test/ui/lint/uninitialized-zeroed.stderr @@ -400,11 +400,8 @@ LL | let _val: Fruit = mem::uninitialized(); note: enums have to be initialized to a variant --> $DIR/uninitialized-zeroed.rs:26:1 | -LL | / enum Fruit { -LL | | Apple, -LL | | Banana, -LL | | } - | |_^ +LL | enum Fruit { + | ^^^^^^^^^^ error: the type `[bool; 2]` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:101:31 diff --git a/src/test/ui/lint/unused/must-use-box-from-raw.rs b/src/test/ui/lint/unused/must-use-box-from-raw.rs new file mode 100644 index 0000000000000..9ea7726894cbc --- /dev/null +++ b/src/test/ui/lint/unused/must-use-box-from-raw.rs @@ -0,0 +1,11 @@ +// #99269 + +// check-pass + +#![warn(unused_must_use)] + +unsafe fn free<T>(ptr: *mut T) { + Box::from_raw(ptr); //~ WARNING unused return value +} + +fn main() {} diff --git a/src/test/ui/lint/unused/must-use-box-from-raw.stderr b/src/test/ui/lint/unused/must-use-box-from-raw.stderr new file mode 100644 index 0000000000000..7769f09aa5203 --- /dev/null +++ b/src/test/ui/lint/unused/must-use-box-from-raw.stderr @@ -0,0 +1,15 @@ +warning: unused return value of `Box::<T>::from_raw` that must be used + --> $DIR/must-use-box-from-raw.rs:8:5 + | +LL | Box::from_raw(ptr); + | ^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/must-use-box-from-raw.rs:5:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + = note: call `drop(from_raw(ptr))` if you intend to drop the `Box` + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr index 30a96af583af7..1a022c30938f2 100644 --- a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -71,7 +71,7 @@ LL | LL | / extern "C" { LL | | fn foo(); LL | | } - | |_- rustdoc does not generate documentation for extern block + | |_- rustdoc does not generate documentation for extern blocks | = help: use `//` for a plain comment diff --git a/src/test/ui/loops/loop-proper-liveness.rs b/src/test/ui/loops/loop-proper-liveness.rs index b242ec4296d66..6546e397785ca 100644 --- a/src/test/ui/loops/loop-proper-liveness.rs +++ b/src/test/ui/loops/loop-proper-liveness.rs @@ -6,7 +6,7 @@ fn test1() { 'a: loop { x = loop { break 'a }; } - println!("{:?}", x); //~ ERROR borrow of possibly-uninitialized variable + println!("{:?}", x); //~ ERROR E0381 } // test2 and test3 should not fail. diff --git a/src/test/ui/loops/loop-proper-liveness.stderr b/src/test/ui/loops/loop-proper-liveness.stderr index 20d5c66a3f205..7504103173652 100644 --- a/src/test/ui/loops/loop-proper-liveness.stderr +++ b/src/test/ui/loops/loop-proper-liveness.stderr @@ -1,8 +1,11 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/loop-proper-liveness.rs:9:22 | +LL | let x: i32; + | - binding declared here but left uninitialized +... LL | println!("{:?}", x); - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr b/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr index 1d57b32d47e86..bf85a2d75db23 100644 --- a/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr +++ b/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr @@ -13,70 +13,60 @@ LL | pong!(); error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> $DIR/main.rs:10:20 | -LL | / macro_rules! pong { -LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens -LL | | } - | |__- in this expansion of `pong!` (#2) +LL | / macro_rules! pong { +LL | | () => { syntax error }; + | | ^^^^^ expected one of 8 possible tokens +LL | | } + | |_- in this expansion of `pong!` (#2) ... -LL | ping!(); - | ------- in this macro invocation (#1) +LL | ping!(); + | ------- in this macro invocation (#1) | ::: $DIR/auxiliary/ping.rs:5:1 | -LL | / macro_rules! ping { -LL | | () => { -LL | | pong!(); - | | ------- in this macro invocation (#2) -LL | | } -LL | | } - | |_- in this expansion of `ping!` (#1) +LL | macro_rules! ping { + | ----------------- in this expansion of `ping!` (#1) +LL | () => { +LL | pong!(); + | ------- in this macro invocation (#2) error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> $DIR/main.rs:10:20 | -LL | / macro_rules! pong { -LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens -LL | | } - | |__- in this expansion of `pong!` (#5) +LL | / macro_rules! pong { +LL | | () => { syntax error }; + | | ^^^^^ expected one of 8 possible tokens +LL | | } + | |_- in this expansion of `pong!` (#5) ... -LL | deep!(); - | ------- in this macro invocation (#1) +LL | deep!(); + | ------- in this macro invocation (#1) | ::: $DIR/auxiliary/ping.rs:5:1 | -LL | / macro_rules! ping { -LL | | () => { -LL | | pong!(); - | | ------- in this macro invocation (#5) -LL | | } -LL | | } - | |_- in this expansion of `ping!` (#4) +LL | macro_rules! ping { + | ----------------- in this expansion of `ping!` (#4) +LL | () => { +LL | pong!(); + | ------- in this macro invocation (#5) ... -LL | / macro_rules! deep { -LL | | () => { -LL | | foo!(); - | | ------ in this macro invocation (#2) -LL | | } -LL | | } - | |__- in this expansion of `deep!` (#1) +LL | macro_rules! deep { + | ----------------- in this expansion of `deep!` (#1) +LL | () => { +LL | foo!(); + | ------ in this macro invocation (#2) ... -LL | / macro_rules! foo { -LL | | () => { -LL | | bar!(); - | | ------ in this macro invocation (#3) -LL | | } -LL | | } - | |__- in this expansion of `foo!` (#2) +LL | macro_rules! foo { + | ---------------- in this expansion of `foo!` (#2) +LL | () => { +LL | bar!(); + | ------ in this macro invocation (#3) ... -LL | / macro_rules! bar { -LL | | () => { -LL | | ping!(); - | | ------- in this macro invocation (#4) -LL | | } -LL | | } - | |__- in this expansion of `bar!` (#3) +LL | macro_rules! bar { + | ---------------- in this expansion of `bar!` (#3) +LL | () => { +LL | ping!(); + | ------- in this macro invocation (#4) error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index 1b58cf9c4ede5..b13e418e664a6 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -1,11 +1,11 @@ -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/issue-68060.rs:4:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | |_| (), - | ------ not a function + | ------ not a function definition error: aborting due to previous error diff --git a/src/test/ui/macros/issue-98466-allow.rs b/src/test/ui/macros/issue-98466-allow.rs new file mode 100644 index 0000000000000..c260148c148d0 --- /dev/null +++ b/src/test/ui/macros/issue-98466-allow.rs @@ -0,0 +1,16 @@ +// check-pass +#![allow(named_arguments_used_positionally)] + +fn main() { + let mut _x: usize; + _x = 1; + println!("_x is {}", _x = 5); + println!("_x is {}", y = _x); + println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + + let mut _x: usize; + _x = 1; + let _f = format!("_x is {}", _x = 5); + let _f = format!("_x is {}", y = _x); + let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); +} diff --git a/src/test/ui/macros/issue-98466.fixed b/src/test/ui/macros/issue-98466.fixed new file mode 100644 index 0000000000000..e46e22f001fe3 --- /dev/null +++ b/src/test/ui/macros/issue-98466.fixed @@ -0,0 +1,51 @@ +// check-pass +// run-rustfix + +fn main() { + let mut _x: usize; + _x = 1; + println!("_x is {_x}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("_x is {y}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let mut _x: usize; + _x = 1; + let _f = format!("_x is {_x}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("_x is {y}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let s = "0.009"; + // Confirm that named arguments used in formatting are correctly considered. + println!(".{:0<width$}", s, width = _x); + + let region = "abc"; + let width = 8; + let ls = "abcde"; + let full = "abcde"; + // Confirm that named arguments used in formatting are correctly considered. + println!( + "| {r:rw$?} | {ui:4?} | {v}", + r = region, + rw = width, + ui = ls, + v = full, + ); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4); +} diff --git a/src/test/ui/macros/issue-98466.rs b/src/test/ui/macros/issue-98466.rs new file mode 100644 index 0000000000000..2c3b099afdeaf --- /dev/null +++ b/src/test/ui/macros/issue-98466.rs @@ -0,0 +1,51 @@ +// check-pass +// run-rustfix + +fn main() { + let mut _x: usize; + _x = 1; + println!("_x is {}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("_x is {}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let mut _x: usize; + _x = 1; + let _f = format!("_x is {}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("_x is {}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let s = "0.009"; + // Confirm that named arguments used in formatting are correctly considered. + println!(".{:0<width$}", s, width = _x); + + let region = "abc"; + let width = 8; + let ls = "abcde"; + let full = "abcde"; + // Confirm that named arguments used in formatting are correctly considered. + println!( + "| {r:rw$?} | {ui:4?} | {v}", + r = region, + rw = width, + ui = ls, + v = full, + ); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4); +} diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr new file mode 100644 index 0000000000000..ad11d181b6218 --- /dev/null +++ b/src/test/ui/macros/issue-98466.stderr @@ -0,0 +1,81 @@ +warning: named argument `_x` is not used by name + --> $DIR/issue-98466.rs:7:26 + | +LL | println!("_x is {}", _x = 5); + | -- ^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position + | + = note: `#[warn(named_arguments_used_positionally)]` on by default +help: use the named argument by name to avoid ambiguity + | +LL | println!("_x is {_x}", _x = 5); + | ~~~~ + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:10:26 + | +LL | println!("_x is {}", y = _x); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("_x is {y}", y = _x); + | ~~~ + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:13:83 + | +LL | println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + | ~~~ + +warning: named argument `_x` is not used by name + --> $DIR/issue-98466.rs:19:34 + | +LL | let _f = format!("_x is {}", _x = 5); + | -- ^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | let _f = format!("_x is {_x}", _x = 5); + | ~~~~ + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:22:34 + | +LL | let _f = format!("_x is {}", y = _x); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | let _f = format!("_x is {y}", y = _x); + | ~~~ + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:25:91 + | +LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + | ~~~ + +warning: 6 warnings emitted + diff --git a/src/test/ui/macros/issue-99261.rs b/src/test/ui/macros/issue-99261.rs new file mode 100644 index 0000000000000..40d26d08cba11 --- /dev/null +++ b/src/test/ui/macros/issue-99261.rs @@ -0,0 +1,17 @@ +// check-pass + +#![deny(named_arguments_used_positionally)] + +fn main() { + let value: f64 = 314.15926; + let digits_before_decimal = 1; + let digits_after_decimal = 2; + let width = digits_before_decimal + 1 + digits_after_decimal; + + println!( + "{value:0>width$.digits_after_decimal$}", + value = value, + width = width, + digits_after_decimal = digits_after_decimal, + ); +} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs deleted file mode 100644 index 1db9d33c72aee..0000000000000 --- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs +++ /dev/null @@ -1,9 +0,0 @@ -// check-pass -// compile-flags: -Z unpretty=expanded - -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] - -fn main() { - let elem = 1i32; - assert!(elem == 1); -} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout deleted file mode 100644 index a590eb3223254..0000000000000 --- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout +++ /dev/null @@ -1,29 +0,0 @@ -#![feature(prelude_import)] -#![no_std] -// check-pass -// compile-flags: -Z unpretty=expanded - -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] -#[prelude_import] -use ::std::prelude::rust_2015::*; -#[macro_use] -extern crate std; - -fn main() { - let elem = 1i32; - { - #[allow(unused_imports)] - use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; - let mut __capture0 = ::core::asserting::Capture::new(); - let __local_bind0 = &elem; - if !(*{ - (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); - __local_bind0 - } == 1) { - { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) - } - } - }; -} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs new file mode 100644 index 0000000000000..5ec84b08ff808 --- /dev/null +++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs @@ -0,0 +1,32 @@ +// check-pass +// compile-flags: -Z unpretty=expanded + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +fn arbitrary_consuming_method_for_demonstration_purposes() { + let elem = 1i32; + assert!(elem as usize); +} + +fn addr_of() { + let elem = 1i32; + assert!(&elem); +} + +fn binary() { + let elem = 1i32; + assert!(elem == 1); + assert!(elem >= 1); + assert!(elem > 0); + assert!(elem < 3); + assert!(elem <= 3); + assert!(elem != 3); +} + +fn unary() { + let elem = &1i32; + assert!(*elem); +} + +fn main() { +} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout new file mode 100644 index 0000000000000..90f858f80e6b5 --- /dev/null +++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -0,0 +1,147 @@ +#![feature(prelude_import)] +#![no_std] +// check-pass +// compile-flags: -Z unpretty=expanded + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +fn arbitrary_consuming_method_for_demonstration_purposes() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*{ + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + __local_bind0 + } as usize)) { + + + + + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn addr_of() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!&*__local_bind0) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn binary() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn unary() { + let elem = &1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!**__local_bind0) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn main() {} diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index 7b04e05293ea1..8f9dba16578eb 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -7,12 +7,8 @@ LL | macro_rules! unknown { () => () } error[E0773]: attempted to define built-in macro more than once --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | -LL | / macro_rules! line { -LL | | () => { -LL | | /* compiler built-in */ -LL | | }; -LL | | } - | |_____^ +LL | macro_rules! line { + | ^^^^^^^^^^^^^^^^^ | note: previously defined here --> $DIR/unknown-builtin.rs:9:1 diff --git a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs index 66156b6e53bab..0bf620934ec7b 100644 --- a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs +++ b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs @@ -1,23 +1,23 @@ #![feature(marker_trait_attr)] -#[marker] //~ ERROR attribute can only be applied to a trait +#[marker] //~ ERROR attribute should be applied to a trait struct Struct {} -#[marker] //~ ERROR attribute can only be applied to a trait +#[marker] //~ ERROR attribute should be applied to a trait impl Struct {} -#[marker] //~ ERROR attribute can only be applied to a trait +#[marker] //~ ERROR attribute should be applied to a trait union Union { x: i32, } -#[marker] //~ ERROR attribute can only be applied to a trait +#[marker] //~ ERROR attribute should be applied to a trait const CONST: usize = 10; -#[marker] //~ ERROR attribute can only be applied to a trait +#[marker] //~ ERROR attribute should be applied to a trait fn function() {} -#[marker] //~ ERROR attribute can only be applied to a trait +#[marker] //~ ERROR attribute should be applied to a trait type Type = (); fn main() {} diff --git a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr index d30b990caac2b..19a5290dd7eb6 100644 --- a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr +++ b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr @@ -1,4 +1,4 @@ -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:3:1 | LL | #[marker] @@ -6,7 +6,7 @@ LL | #[marker] LL | struct Struct {} | ---------------- not a trait -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:6:1 | LL | #[marker] @@ -14,7 +14,7 @@ LL | #[marker] LL | impl Struct {} | -------------- not a trait -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:9:1 | LL | #[marker] @@ -24,7 +24,7 @@ LL | | x: i32, LL | | } | |_- not a trait -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:14:1 | LL | #[marker] @@ -32,7 +32,7 @@ LL | #[marker] LL | const CONST: usize = 10; | ------------------------ not a trait -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:17:1 | LL | #[marker] @@ -40,7 +40,7 @@ LL | #[marker] LL | fn function() {} | ---------------- not a trait -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/marker-attribute-on-non-trait.rs:20:1 | LL | #[marker] diff --git a/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr index ae7d5a98b0872..ac218e30b9b85 100644 --- a/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr +++ b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr @@ -2,13 +2,13 @@ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:6:5 | LL | const N: usize; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:12:5 | LL | type Output; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:18:5 @@ -20,13 +20,13 @@ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:24:5 | LL | const N: usize = 43; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:30:5 | LL | type Output = (); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error[E0714]: marker traits cannot have associated items --> $DIR/marker-trait-with-associated-items.rs:36:5 diff --git a/src/test/ui/marker_trait_attr/region-overlap.stderr b/src/test/ui/marker_trait_attr/region-overlap.stderr index 2eeab801e3d9c..6631fe987e275 100644 --- a/src/test/ui/marker_trait_attr/region-overlap.stderr +++ b/src/test/ui/marker_trait_attr/region-overlap.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `(&'static (), &'a ()): A` --> $DIR/region-overlap.rs:5:10 | LL | impl<'a> A for (&'static (), &'a ()) {} - | ^ cannot infer type for tuple `(&'static (), &'a ())` + | ^ | note: multiple `impl`s satisfying `(&'static (), &'a ()): A` found --> $DIR/region-overlap.rs:5:1 @@ -12,11 +12,11 @@ LL | impl<'a> A for (&'static (), &'a ()) {} LL | impl<'a> A for (&'a (), &'static ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `(&'a (), &'static ()): A` --> $DIR/region-overlap.rs:6:10 | LL | impl<'a> A for (&'a (), &'static ()) {} - | ^ cannot infer type for tuple `(&'a (), &'static ())` + | ^ | note: multiple `impl`s satisfying `(&'a (), &'static ()): A` found --> $DIR/region-overlap.rs:5:1 diff --git a/src/test/ui/match/match_non_exhaustive.stderr b/src/test/ui/match/match_non_exhaustive.stderr index 6206dc85ea05f..9d92f8fdbb4b3 100644 --- a/src/test/ui/match/match_non_exhaustive.stderr +++ b/src/test/ui/match/match_non_exhaustive.stderr @@ -25,7 +25,7 @@ note: `E1` defined here --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1 | LL | pub enum E1 {} - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ = note: the matched value is of type `E1`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -44,7 +44,7 @@ note: `E2` defined here --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1 | LL | pub enum E2 { A, B } - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ = note: the matched value is of type `E2`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/methods/issues/issue-61525.rs b/src/test/ui/methods/issues/issue-61525.rs new file mode 100644 index 0000000000000..c5ca0326e430c --- /dev/null +++ b/src/test/ui/methods/issues/issue-61525.rs @@ -0,0 +1,20 @@ +pub trait Example { + fn query<Q>(self, q: Q); +} + +impl Example for i32 { + fn query<Q>(self, _: Q) { + unimplemented!() + } +} + +mod nested { + use super::Example; + fn example() { + 1.query::<dyn ToString>("") + //~^ ERROR the size for values of type `dyn ToString` cannot be known at compilation time + //~| ERROR mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/methods/issues/issue-61525.stderr b/src/test/ui/methods/issues/issue-61525.stderr new file mode 100644 index 0000000000000..aec968d7c44f4 --- /dev/null +++ b/src/test/ui/methods/issues/issue-61525.stderr @@ -0,0 +1,39 @@ +error[E0277]: the size for values of type `dyn ToString` cannot be known at compilation time + --> $DIR/issue-61525.rs:14:33 + | +LL | 1.query::<dyn ToString>("") + | ----- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `dyn ToString` +note: required by a bound in `Example::query` + --> $DIR/issue-61525.rs:2:14 + | +LL | fn query<Q>(self, q: Q); + | ^ required by this bound in `Example::query` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn query<Q: ?Sized>(self, q: Q); + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-61525.rs:14:33 + | +LL | 1.query::<dyn ToString>("") + | --------------------- ^^ expected trait object `dyn ToString`, found `&str` + | | + | arguments to this function are incorrect + | + = note: expected trait object `dyn ToString` + found reference `&'static str` +note: associated function defined here + --> $DIR/issue-61525.rs:2:8 + | +LL | fn query<Q>(self, q: Q); + | ^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 66e7ada3ac5fd..e0f8a5447b081 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -13,7 +13,7 @@ error[E0283]: type annotations needed --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7 | LL | x.foo(); - | ^^^ cannot infer type for struct `Vec<_>` + | ^^^ | note: multiple `impl`s satisfying `Vec<_>: Foo` found --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1 @@ -23,6 +23,10 @@ LL | impl Foo for Vec<usize> { ... LL | impl Foo for Vec<isize> { | ^^^^^^^^^^^^^^^^^^^^^^^ +help: try using a fully qualified path to specify the expected types + | +LL | <Vec<T> as Foo>::foo(&x); + | ++++++++++++++++++++++ ~ error[E0308]: mismatched types --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index 95edee6ad23e8..690fe8fa7af10 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:13:7 | LL | x.zero(0) - | ^^^^ - argument unexpected + | ^^^^ - argument of type `{integer}` unexpected | note: associated function defined here --> $DIR/method-call-err-msg.rs:5:8 @@ -50,9 +50,9 @@ error[E0599]: `Foo` is not an iterator --> $DIR/method-call-err-msg.rs:19:7 | LL | pub struct Foo; - | --------------- + | -------------- | | - | method `take` not found for this + | method `take` not found for this struct | doesn't satisfy `Foo: Iterator` ... LL | .take() @@ -64,14 +64,8 @@ LL | .take() note: the following trait must be implemented --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | -LL | / pub trait Iterator { -LL | | /// The type of the elements being iterated over. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Item; -... | -LL | | } -LL | | } - | |_^ +LL | pub trait Iterator { + | ^^^^^^^^^^^^^^^^^^ = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `take`, perhaps you need to implement it: candidate #1: `Iterator` diff --git a/src/test/ui/methods/method-macro-backtrace.stderr b/src/test/ui/methods/method-macro-backtrace.stderr index 7860365476a31..7ae00835c965d 100644 --- a/src/test/ui/methods/method-macro-backtrace.stderr +++ b/src/test/ui/methods/method-macro-backtrace.stderr @@ -2,9 +2,9 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/method-macro-backtrace.rs:22:5 | LL | fn bar(&self) { } - | ----------------- previous definition of `bar` here + | ------------- previous definition of `bar` here LL | fn bar(&self) { } - | ^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr index 045f9ab700420..040a65d168091 100644 --- a/src/test/ui/methods/method-missing-call.stderr +++ b/src/test/ui/methods/method-missing-call.stderr @@ -9,7 +9,7 @@ help: use parentheses to call the method LL | .get_x(); | ++ -error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` +error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:23]>, [closure@$DIR/method-missing-call.rs:28:23: 28:28]>` --> $DIR/method-missing-call.rs:29:16 | LL | .filter_map; diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr index 1671e5e5e64c8..56e1b5a0f4473 100644 --- a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `distance` found for struct `Point<i32>` in the cu --> $DIR/method-not-found-generic-arg-elision.rs:82:23 | LL | struct Point<T> { - | --------------- method `distance` not found for this + | --------------- method `distance` not found for this struct ... LL | let d = point_i32.distance(); | ^^^^^^^^ method not found in `Point<i32>` @@ -14,7 +14,7 @@ error[E0599]: no method named `other` found for struct `Point` in the current sc --> $DIR/method-not-found-generic-arg-elision.rs:84:23 | LL | struct Point<T> { - | --------------- method `other` not found for this + | --------------- method `other` not found for this struct ... LL | let d = point_i32.other(); | ^^^^^ method not found in `Point<i32>` @@ -23,13 +23,13 @@ error[E0599]: no method named `extend` found for struct `Map` in the current sco --> $DIR/method-not-found-generic-arg-elision.rs:87:29 | LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); - | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>` + | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>` error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:90:13 | LL | struct Wrapper<T>(T); - | --------------------- method `method` not found for this + | ----------------- method `method` not found for this struct ... LL | wrapper.method(); | ^^^^^^ method not found in `Wrapper<bool>` @@ -45,7 +45,7 @@ error[E0599]: no method named `other` found for struct `Wrapper` in the current --> $DIR/method-not-found-generic-arg-elision.rs:92:13 | LL | struct Wrapper<T>(T); - | --------------------- method `other` not found for this + | ----------------- method `other` not found for this struct ... LL | wrapper.other(); | ^^^^^ method not found in `Wrapper<bool>` @@ -54,7 +54,7 @@ error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_us --> $DIR/method-not-found-generic-arg-elision.rs:96:13 | LL | struct Wrapper2<'a, T, const C: usize> { - | -------------------------------------- method `method` not found for this + | -------------------------------------- method `method` not found for this struct ... LL | wrapper.method(); | ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` @@ -68,7 +68,7 @@ error[E0599]: no method named `other` found for struct `Wrapper2` in the current --> $DIR/method-not-found-generic-arg-elision.rs:98:13 | LL | struct Wrapper2<'a, T, const C: usize> { - | -------------------------------------- method `other` not found for this + | -------------------------------------- method `other` not found for this struct ... LL | wrapper.other(); | ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` @@ -83,7 +83,7 @@ error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait --> $DIR/method-not-found-generic-arg-elision.rs:104:7 | LL | struct Struct<T>{ - | ---------------- method `method` not found for this + | ---------------- method `method` not found for this struct ... LL | s.method(); | ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs index c44dd51a5ec86..fc7341a563bb2 100644 --- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs +++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs @@ -6,7 +6,7 @@ static A: () = { //~^ ERROR destructors cannot be evaluated at compile-time a[0] = String::new(); //~^ ERROR destructors cannot be evaluated at compile-time - //~| ERROR use of possibly-uninitialized variable + //~| ERROR binding `a` isn't initialized }; struct B<T>([T; 1]); diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr index 80d5fc7ec672c..d8154f8d2cbc4 100644 --- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr +++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr @@ -16,11 +16,14 @@ LL | let a: [String; 1]; LL | }; | - value is dropped here -error[E0381]: use of possibly-uninitialized variable: `a` +error[E0381]: used binding `a` isn't initialized --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5 | +LL | let a: [String; 1]; + | - binding declared here but left uninitialized +LL | LL | a[0] = String::new(); - | ^^^^ use of possibly-uninitialized `a` + | ^^^^ `a` used here but it isn't initialized error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9 diff --git a/src/test/ui/mir/issue-67947.rs b/src/test/ui/mir/issue-67947.rs index 79e75e655ff1f..f73d38f80426f 100644 --- a/src/test/ui/mir/issue-67947.rs +++ b/src/test/ui/mir/issue-67947.rs @@ -1,6 +1,6 @@ struct Bug { A: [(); { *"" }.len()], - //~^ ERROR: cannot move a value of type str + //~^ ERROR: cannot move a value of type `str` //~| ERROR: cannot move out of a shared reference } diff --git a/src/test/ui/mir/issue-67947.stderr b/src/test/ui/mir/issue-67947.stderr index d526218162076..7697a411eb481 100644 --- a/src/test/ui/mir/issue-67947.stderr +++ b/src/test/ui/mir/issue-67947.stderr @@ -1,8 +1,8 @@ -error[E0161]: cannot move a value of type str: the size of str cannot be statically determined +error[E0161]: cannot move a value of type `str` --> $DIR/issue-67947.rs:2:13 | LL | A: [(); { *"" }.len()], - | ^^^^^^^ + | ^^^^^^^ the size of `str` cannot be statically determined error[E0507]: cannot move out of a shared reference --> $DIR/issue-67947.rs:2:15 diff --git a/src/test/ui/mir/issue-92893.rs b/src/test/ui/mir/issue-92893.rs index d2bbb4f110114..c2827c7e37fcb 100644 --- a/src/test/ui/mir/issue-92893.rs +++ b/src/test/ui/mir/issue-92893.rs @@ -1,6 +1,6 @@ struct Bug<A = [(); (let a = (), 1).1]> { //~^ `let` expressions are not supported here - //~^^ `let` expressions in this position are unstable [E0658] + //~| expected expression, found `let` statement a: A } diff --git a/src/test/ui/mir/issue-92893.stderr b/src/test/ui/mir/issue-92893.stderr index 063b5d66feb45..bd4654edf4b34 100644 --- a/src/test/ui/mir/issue-92893.stderr +++ b/src/test/ui/mir/issue-92893.stderr @@ -1,20 +1,16 @@ -error: `let` expressions are not supported here +error: expected expression, found `let` statement --> $DIR/issue-92893.rs:1:22 | LL | struct Bug<A = [(); (let a = (), 1).1]> { - | ^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions + | ^^^ -error[E0658]: `let` expressions in this position are unstable +error: `let` expressions are not supported here --> $DIR/issue-92893.rs:1:22 | LL | struct Bug<A = [(); (let a = (), 1).1]> { | ^^^^^^^^^^ | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: only supported directly in conditions of `if` and `while` expressions error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/mir/mir_let_chains_drop_order.rs b/src/test/ui/mir/mir_let_chains_drop_order.rs index 6498a51957194..21e7b5070af62 100644 --- a/src/test/ui/mir/mir_let_chains_drop_order.rs +++ b/src/test/ui/mir/mir_let_chains_drop_order.rs @@ -4,7 +4,6 @@ // See `mir_drop_order.rs` for more information -#![feature(let_chains)] #![allow(irrefutable_let_patterns)] use std::cell::RefCell; diff --git a/src/test/ui/mir/ssa-analysis-regression-50041.rs b/src/test/ui/mir/ssa-analysis-regression-50041.rs index 8e9c14a03c386..ebc3e2f8c0e31 100644 --- a/src/test/ui/mir/ssa-analysis-regression-50041.rs +++ b/src/test/ui/mir/ssa-analysis-regression-50041.rs @@ -5,7 +5,7 @@ #![feature(lang_items)] #![no_std] -struct NonNull<T: ?Sized>(*mut T); +struct NonNull<T: ?Sized>(*const T); struct Unique<T: ?Sized>(NonNull<T>); @@ -23,7 +23,7 @@ unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) { } #[inline(never)] -fn dealloc<T: ?Sized>(_: *mut T) {} +fn dealloc<T: ?Sized>(_: *const T) {} pub struct Foo<T>(T); diff --git a/src/test/ui/mismatched_types/assignment-operator-unimplemented.stderr b/src/test/ui/mismatched_types/assignment-operator-unimplemented.stderr index 73c9f86e00220..ffd95b48ac2b7 100644 --- a/src/test/ui/mismatched_types/assignment-operator-unimplemented.stderr +++ b/src/test/ui/mismatched_types/assignment-operator-unimplemented.stderr @@ -10,18 +10,12 @@ note: an implementation of `AddAssign<_>` might be missing for `Foo` --> $DIR/assignment-operator-unimplemented.rs:1:1 | LL | struct Foo; - | ^^^^^^^^^^^ must implement `AddAssign<_>` + | ^^^^^^^^^^ must implement `AddAssign<_>` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait AddAssign<Rhs = Self> { -LL | | /// Performs the `+=` operation. -LL | | /// -LL | | /// # Example -... | -LL | | fn add_assign(&mut self, rhs: Rhs); -LL | | } - | |_^ +LL | pub trait AddAssign<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index e63ca6e11de59..eab8e8e80c424 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -220,7 +220,7 @@ LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast from `[u8]` to the object type `dyn Foo` help: consider borrowing the value, since `&[u8]` can be coerced into `dyn Foo` | LL | let _ = &fat_v as *const dyn Foo; @@ -233,7 +233,7 @@ LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn Foo` + = note: required for the cast from `str` to the object type `dyn Foo` help: consider borrowing the value, since `&str` can be coerced into `dyn Foo` | LL | let _ = &a as *const dyn Foo; diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index fed47e0f17471..3968774e35793 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -188,7 +188,7 @@ LL | call(Foo); | required by a bound introduced by this call ... LL | struct Foo(u8); - | --------------- takes 1 argument + | ---------- takes 1 argument | note: required by a bound in `call` --> $DIR/closure-arg-count.rs:42:30 diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 1f46229cb5a6a..d9578f6c8dcf6 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -2,7 +2,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:3:14 | LL | a.iter().map(|_: (u32, u32)| 45); - | ^^^ ------------------ found signature of `fn((u32, u32)) -> _` + | ^^^ --------------- found signature of `fn((u32, u32)) -> _` | | | expected signature of `fn(&(u32, u32)) -> _` | @@ -16,7 +16,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:4:14 | LL | a.iter().map(|_: &(u16, u16)| 45); - | ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _` + | ^^^ ---------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _` | | | expected signature of `fn(&(u32, u32)) -> _` | @@ -30,7 +30,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/closure-arg-type-mismatch.rs:5:14 | LL | a.iter().map(|_: (u16, u16)| 45); - | ^^^ ------------------ found signature of `fn((u16, u16)) -> _` + | ^^^ --------------- found signature of `fn((u16, u16)) -> _` | | | expected signature of `fn(&(u32, u32)) -> _` | diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index c1a29dfc9339f..ef76ec63fdaf8 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -19,7 +19,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:8:9 | LL | baz(|_| ()); - | ^^^^^^ + | ^^^ note: the lifetime requirement is introduced here --> $DIR/closure-mismatch.rs:5:11 | diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index a8bcdf5efe91e..9d1ea70f8a4a4 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -2,7 +2,7 @@ error[E0631]: type mismatch in closure arguments --> $DIR/issue-36053-2.rs:7:32 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` + | ^^^^^^ --------- found signature of `for<'r> fn(&'r str) -> _` | | | expected signature of `for<'r> fn(&'r &str) -> _` | @@ -12,11 +12,11 @@ note: required by a bound in `filter` LL | P: FnMut(&Self::Item) -> bool, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter` -error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`, but its trait bounds were not satisfied +error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied --> $DIR/issue-36053-2.rs:7:55 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | -------------- ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` due to unsatisfied trait bounds + | --------- ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>` due to unsatisfied trait bounds | | | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` | doesn't satisfy `_: FnMut<(&&str,)>` @@ -27,12 +27,12 @@ LL | pub struct Filter<I, P> { | ----------------------- doesn't satisfy `_: Iterator` | = note: the following trait bounds were not satisfied: - `<[closure@$DIR/issue-36053-2.rs:7:39: 7:53] as FnOnce<(&&str,)>>::Output = bool` - which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` - `[closure@$DIR/issue-36053-2.rs:7:39: 7:53]: FnMut<(&&str,)>` - which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` - `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` - which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + `<[closure@$DIR/issue-36053-2.rs:7:39: 7:48] as FnOnce<(&&str,)>>::Output = bool` + which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` + `[closure@$DIR/issue-36053-2.rs:7:39: 7:48]: FnMut<(&&str,)>` + which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` + `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` + which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/issue-47706.stderr b/src/test/ui/mismatched_types/issue-47706.stderr index 0b4f84a330a54..8b8563684014d 100644 --- a/src/test/ui/mismatched_types/issue-47706.stderr +++ b/src/test/ui/mismatched_types/issue-47706.stderr @@ -19,7 +19,7 @@ error[E0593]: function is expected to take 0 arguments, but it takes 1 argument --> $DIR/issue-47706.rs:27:9 | LL | Bar(i32), - | -------- takes 1 argument + | --- takes 1 argument ... LL | foo(Qux::Bar); | --- ^^^^^^^^ expected function that takes 0 arguments diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 4000b2ba31245..475ea9dfaf1b4 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -6,11 +6,11 @@ LL | let ans = s("what"); | | | arguments to this function are incorrect | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:10:1 | -LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; - | ^^^^^^^^ +LL | impl FnMut<(isize,)> for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/overloaded-calls-bad.rs:29:15 @@ -18,11 +18,11 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied LL | let ans = s(); | ^-- an argument of type `isize` is missing | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:10:1 | -LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; - | ^^^^^^^^ +LL | impl FnMut<(isize,)> for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: provide the argument | LL | let ans = s(/* isize */); @@ -32,15 +32,15 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:31:15 | LL | let ans = s("burma", "shave"); - | ^ ------- ------- argument unexpected + | ^ ------- ------- argument of type `&'static str` unexpected | | | expected `isize`, found `&str` | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:10:1 | -LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; - | ^^^^^^^^ +LL | impl FnMut<(isize,)> for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the extra argument | LL | let ans = s(/* isize */); diff --git a/src/test/ui/mismatched_types/ref-pat-suggestions.fixed b/src/test/ui/mismatched_types/ref-pat-suggestions.fixed index ab8483eef49fa..d50acd1ac62d2 100644 --- a/src/test/ui/mismatched_types/ref-pat-suggestions.fixed +++ b/src/test/ui/mismatched_types/ref-pat-suggestions.fixed @@ -21,4 +21,17 @@ fn main() { let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types let _ = |&_a: &u32| (); //~ ERROR mismatched types let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types + + #[allow(unused_mut)] + { + struct S(u8); + + let mut _a = 0; //~ ERROR mismatched types + let S(_b) = S(0); //~ ERROR mismatched types + let (_c,) = (0,); //~ ERROR mismatched types + + match 0 { + _d => {} //~ ERROR mismatched types + } + } } diff --git a/src/test/ui/mismatched_types/ref-pat-suggestions.rs b/src/test/ui/mismatched_types/ref-pat-suggestions.rs index 7e55539aa3d1b..1a77f68769224 100644 --- a/src/test/ui/mismatched_types/ref-pat-suggestions.rs +++ b/src/test/ui/mismatched_types/ref-pat-suggestions.rs @@ -21,4 +21,17 @@ fn main() { let _ = |&mut &_a: &mut u32| (); //~ ERROR mismatched types let _ = |&&mut _a: &u32| (); //~ ERROR mismatched types let _ = |&mut &mut _a: &mut u32| (); //~ ERROR mismatched types + + #[allow(unused_mut)] + { + struct S(u8); + + let &mut _a = 0; //~ ERROR mismatched types + let S(&mut _b) = S(0); //~ ERROR mismatched types + let (&mut _c,) = (0,); //~ ERROR mismatched types + + match 0 { + &mut _d => {} //~ ERROR mismatched types + } + } } diff --git a/src/test/ui/mismatched_types/ref-pat-suggestions.stderr b/src/test/ui/mismatched_types/ref-pat-suggestions.stderr index 0e8f8853fb751..d9501a9bbc61e 100644 --- a/src/test/ui/mismatched_types/ref-pat-suggestions.stderr +++ b/src/test/ui/mismatched_types/ref-pat-suggestions.stderr @@ -24,6 +24,11 @@ LL | fn _f1(&mut _a: u32) {} | = note: expected type `u32` found mutable reference `&mut _` +note: to declare a mutable parameter use: `mut _a` + --> $DIR/ref-pat-suggestions.rs:4:8 + | +LL | fn _f1(&mut _a: u32) {} + | ^^^^^^^ help: to take parameter `_a` by reference, move `&mut` to the type | LL - fn _f1(&mut _a: u32) {} @@ -122,6 +127,11 @@ LL | let _: fn(u32) = |&mut _a| (); | = note: expected type `u32` found mutable reference `&mut _` +note: to declare a mutable parameter use: `mut _a` + --> $DIR/ref-pat-suggestions.rs:12:23 + | +LL | let _: fn(u32) = |&mut _a| (); + | ^^^^^^^ help: consider removing `&mut` from the pattern | LL - let _: fn(u32) = |&mut _a| (); @@ -222,6 +232,11 @@ LL | let _ = |&mut _a: u32| (); | = note: expected type `u32` found mutable reference `&mut _` +note: to declare a mutable parameter use: `mut _a` + --> $DIR/ref-pat-suggestions.rs:19:14 + | +LL | let _ = |&mut _a: u32| (); + | ^^^^^^^ help: to take parameter `_a` by reference, move `&mut` to the type | LL - let _ = |&mut _a: u32| (); @@ -292,6 +307,81 @@ LL - let _ = |&mut &mut _a: &mut u32| (); LL + let _ = |&mut _a: &mut u32| (); | -error: aborting due to 18 previous errors +error[E0308]: mismatched types + --> $DIR/ref-pat-suggestions.rs:29:13 + | +LL | let &mut _a = 0; + | ^^^^^^^ - this expression has type `{integer}` + | | + | expected integer, found `&mut _` + | help: to declare a mutable variable use: `mut _a` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref-pat-suggestions.rs:30:15 + | +LL | let S(&mut _b) = S(0); + | ^^^^^^^ ---- this expression has type `S` + | | + | expected `u8`, found `&mut _` + | + = note: expected type `u8` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut _b` + --> $DIR/ref-pat-suggestions.rs:30:15 + | +LL | let S(&mut _b) = S(0); + | ^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let S(&mut _b) = S(0); +LL + let S(_b) = S(0); + | + +error[E0308]: mismatched types + --> $DIR/ref-pat-suggestions.rs:31:14 + | +LL | let (&mut _c,) = (0,); + | ^^^^^^^ ---- this expression has type `({integer},)` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut _c` + --> $DIR/ref-pat-suggestions.rs:31:14 + | +LL | let (&mut _c,) = (0,); + | ^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let (&mut _c,) = (0,); +LL + let (_c,) = (0,); + | + +error[E0308]: mismatched types + --> $DIR/ref-pat-suggestions.rs:34:13 + | +LL | match 0 { + | - this expression has type `{integer}` +LL | &mut _d => {} + | ^^^^^^^ expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut _d` + --> $DIR/ref-pat-suggestions.rs:34:13 + | +LL | &mut _d => {} + | ^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - &mut _d => {} +LL + _d => {} + | + +error: aborting due to 22 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/missing-trait-bounds/issue-69725.stderr b/src/test/ui/missing-trait-bounds/issue-69725.stderr index 6395bca300c92..980d9dd167d20 100644 --- a/src/test/ui/missing-trait-bounds/issue-69725.stderr +++ b/src/test/ui/missing-trait-bounds/issue-69725.stderr @@ -7,7 +7,7 @@ LL | let _ = Struct::<A>::new().clone(); ::: $DIR/auxiliary/issue-69725.rs:2:1 | LL | pub struct Struct<A>(A); - | ------------------------ doesn't satisfy `Struct<A>: Clone` + | -------------------- doesn't satisfy `Struct<A>: Clone` | = note: the following trait bounds were not satisfied: `A: Clone` diff --git a/src/test/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr b/src/test/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr index f3c6b39e62ed0..9e94aa2c7b3b9 100644 --- a/src/test/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr +++ b/src/test/ui/missing-trait-bounds/missing-trait-bounds-for-method-call.stderr @@ -30,7 +30,7 @@ error[E0599]: the method `foo` exists for reference `&Fin<T>`, but its trait bou --> $DIR/missing-trait-bounds-for-method-call.rs:27:14 | LL | struct Fin<T> where T: Bar { - | -------------------------- doesn't satisfy `Fin<T>: Bar` + | ------------- doesn't satisfy `Fin<T>: Bar` ... LL | self.foo(); | ^^^ method cannot be called on `&Fin<T>` due to unsatisfied trait bounds diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs index e6bc4e22ec22c..d76b69ecdc8bb 100644 --- a/src/test/ui/moves/issue-72649-uninit-in-loop.rs +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs @@ -57,17 +57,17 @@ fn moved_loop_2() { fn uninit_1() { loop { - let value: NonCopy; - let _used = value; //~ ERROR use of possibly-uninitialized variable: `value` - //~^ NOTE use of possibly-uninitialized `value` + let value: NonCopy; //~ NOTE declared here + let _used = value; //~ ERROR binding `value` isn't initialized + //~^ NOTE `value` used here but it isn't initialized } } fn uninit_2() { - let mut value: NonCopy; + let mut value: NonCopy; //~ NOTE declared here loop { - let _used = value; //~ ERROR use of possibly-uninitialized variable: `value` - //~^ NOTE use of possibly-uninitialized `value` + let _used = value; //~ ERROR binding `value` isn't initialized + //~^ NOTE `value` used here but it isn't initialized } } diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr index 076d3dff14086..c7373b5be9d8d 100644 --- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr @@ -40,17 +40,22 @@ LL | let mut value = NonCopy{}; LL | let _used2 = value; | ^^^^^ value moved here, in previous iteration of loop -error[E0381]: use of possibly-uninitialized variable: `value` +error[E0381]: used binding `value` isn't initialized --> $DIR/issue-72649-uninit-in-loop.rs:61:21 | +LL | let value: NonCopy; + | ----- binding declared here but left uninitialized LL | let _used = value; - | ^^^^^ use of possibly-uninitialized `value` + | ^^^^^ `value` used here but it isn't initialized -error[E0381]: use of possibly-uninitialized variable: `value` +error[E0381]: used binding `value` isn't initialized --> $DIR/issue-72649-uninit-in-loop.rs:69:21 | +LL | let mut value: NonCopy; + | --------- binding declared here but left uninitialized +LL | loop { LL | let _used = value; - | ^^^^^ use of possibly-uninitialized `value` + | ^^^^^ `value` used here but it isn't initialized error: aborting due to 6 previous errors diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr index e3bdf6d783207..5760f4a7fdc35 100644 --- a/src/test/ui/moves/move-deref-coercion.stderr +++ b/src/test/ui/moves/move-deref-coercion.stderr @@ -12,7 +12,7 @@ note: deref defined here --> $DIR/move-deref-coercion.rs:17:5 | LL | type Target = NotCopy; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error[E0382]: borrow of partially moved value: `val` --> $DIR/move-deref-coercion.rs:30:5 @@ -28,7 +28,7 @@ note: deref defined here --> $DIR/move-deref-coercion.rs:17:5 | LL | type Target = NotCopy; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/move-into-dead-array-1.rs b/src/test/ui/moves/move-into-dead-array-1.rs index 2d0ff58526393..0b8d76def872c 100644 --- a/src/test/ui/moves/move-into-dead-array-1.rs +++ b/src/test/ui/moves/move-into-dead-array-1.rs @@ -11,5 +11,5 @@ fn main() { fn foo(i: usize) { let mut a: [D; 4]; - a[i] = d(); //~ ERROR use of possibly-uninitialized variable: `a` + a[i] = d(); //~ ERROR E0381 } diff --git a/src/test/ui/moves/move-into-dead-array-1.stderr b/src/test/ui/moves/move-into-dead-array-1.stderr index 5f20ccfeddf48..344a6bbf0c92c 100644 --- a/src/test/ui/moves/move-into-dead-array-1.stderr +++ b/src/test/ui/moves/move-into-dead-array-1.stderr @@ -1,8 +1,10 @@ -error[E0381]: use of possibly-uninitialized variable: `a` +error[E0381]: used binding `a` isn't initialized --> $DIR/move-into-dead-array-1.rs:14:5 | +LL | let mut a: [D; 4]; + | ----- binding declared here but left uninitialized LL | a[i] = d(); - | ^^^^ use of possibly-uninitialized `a` + | ^^^^ `a` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/moves/move-of-addr-of-mut.rs b/src/test/ui/moves/move-of-addr-of-mut.rs index f2f64e43cd2de..19fd7028692d4 100644 --- a/src/test/ui/moves/move-of-addr-of-mut.rs +++ b/src/test/ui/moves/move-of-addr-of-mut.rs @@ -5,7 +5,7 @@ struct S; fn main() { let mut x: S; - std::ptr::addr_of_mut!(x); //~ borrow of + std::ptr::addr_of_mut!(x); //~ ERROR E0381 let y = x; // Should error here if `addr_of_mut` is ever allowed on uninitialized variables drop(y); diff --git a/src/test/ui/moves/move-of-addr-of-mut.stderr b/src/test/ui/moves/move-of-addr-of-mut.stderr index ce8fb0283165c..e75f2b1c0894c 100644 --- a/src/test/ui/moves/move-of-addr-of-mut.stderr +++ b/src/test/ui/moves/move-of-addr-of-mut.stderr @@ -1,8 +1,10 @@ -error[E0381]: borrow of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/move-of-addr-of-mut.rs:8:5 | +LL | let mut x: S; + | ----- binding declared here but left uninitialized LL | std::ptr::addr_of_mut!(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `x` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `x` used here but it isn't initialized | = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index ce930eee2e919..125e446c33259 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -4,9 +4,8 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure LL | let i = Box::new(3); | - captured outer variable LL | let _f = to_fn(|| test(i)); - | --------^- - | | | - | | move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait + | -- ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait + | | | captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr index 5a84e3b81a656..3e37fcb2141fc 100644 --- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr @@ -143,36 +143,36 @@ LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>) | ++++++++++++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9 | -LL | fn existing_colon_in_where<T>(t: T) - | - move occurs because `t` has type `T`, which does not implement the `Copy` trait -... +LL | fn existing_colon<T:>(t: T) { + | - move occurs because `t` has type `T`, which does not implement the `Copy` trait +LL | LL | [t, t]; | - ^ value used here after move | | | value moved here | -help: consider further restricting type parameter `T` +help: consider restricting type parameter `T` | -LL | T:, T: Copy - | ~~~~~~~~~ +LL | fn existing_colon<T: Copy>(t: T) { + | ++++ error[E0382]: use of moved value: `t` - --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9 + --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9 | -LL | fn existing_colon<T:>(t: T) { - | - move occurs because `t` has type `T`, which does not implement the `Copy` trait -LL | +LL | fn existing_colon_in_where<T>(t: T) + | - move occurs because `t` has type `T`, which does not implement the `Copy` trait +... LL | [t, t]; | - ^ value used here after move | | | value moved here | -help: consider restricting type parameter `T` +help: consider further restricting type parameter `T` | -LL | fn existing_colon<T: Copy>(t: T) { - | ++++ +LL | T:, T: Copy + | ~~~~~~~~~ error: aborting due to 11 previous errors diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr index ccdd4dd272e9b..b04ea14d1a580 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -33,7 +33,7 @@ LL | check(xm1::S); ::: $DIR/auxiliary/namespace-mix.rs:3:5 | LL | pub struct TS(); - | ---------------- similarly named tuple struct `TS` defined here + | ------------- similarly named tuple struct `TS` defined here | = note: can't use a type alias as a constructor help: a tuple struct with a similar name exists @@ -94,7 +94,7 @@ LL | check(xm7::V); LL | V {}, | - `xm7::V` defined here LL | TV(), - | ---- similarly named tuple variant `TV` defined here + | -- similarly named tuple variant `TV` defined here | help: use struct literal syntax instead | diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr index 78d1a3caf4a30..2acf44432c65f 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 21:6] as FnOnce<()>>::Output == ()` +error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()` --> $DIR/fallback-closure-wrap.rs:18:31 | LL | let error = Closure::wrap(Box::new(move || { @@ -10,7 +10,7 @@ LL | | }) as Box<dyn FnMut()>); | = note: expected unit type `()` found type `!` - = note: required for the cast to the object type `dyn FnMut()` + = note: required for the cast from `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to the object type `dyn FnMut()` error: aborting due to previous error diff --git a/src/test/ui/never_type/impl_trait_fallback2.rs b/src/test/ui/never_type/impl_trait_fallback2.rs index f73d953bdbd0b..12c187b9e82aa 100644 --- a/src/test/ui/never_type/impl_trait_fallback2.rs +++ b/src/test/ui/never_type/impl_trait_fallback2.rs @@ -13,6 +13,7 @@ fn should_ret_unit() -> impl T { type Foo = impl T; fn a() -> Foo { + //~^ ERROR `(): T` is not satisfied panic!() } diff --git a/src/test/ui/never_type/impl_trait_fallback2.stderr b/src/test/ui/never_type/impl_trait_fallback2.stderr index 4a78e73e5f6d5..78cc83bdbfadb 100644 --- a/src/test/ui/never_type/impl_trait_fallback2.stderr +++ b/src/test/ui/never_type/impl_trait_fallback2.stderr @@ -6,6 +6,14 @@ LL | fn should_ret_unit() -> impl T { | = help: the trait `T` is implemented for `i32` -error: aborting due to previous error +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/impl_trait_fallback2.rs:15:11 + | +LL | fn a() -> Foo { + | ^^^ the trait `T` is not implemented for `()` + | + = help: the trait `T` is implemented for `i32` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/impl_trait_fallback3.rs b/src/test/ui/never_type/impl_trait_fallback3.rs index 26ce9b93105e6..ed645b82394a0 100644 --- a/src/test/ui/never_type/impl_trait_fallback3.rs +++ b/src/test/ui/never_type/impl_trait_fallback3.rs @@ -7,9 +7,9 @@ trait T { } type Foo = impl T; -//~^ ERROR unconstrained opaque type fn a() -> Foo { + //~^ ERROR the trait bound `(): T` is not satisfied // This is not a defining use, it doesn't actually constrain the opaque type. panic!() } diff --git a/src/test/ui/never_type/impl_trait_fallback3.stderr b/src/test/ui/never_type/impl_trait_fallback3.stderr index 121019d5f69ae..5d5d216fb9bcc 100644 --- a/src/test/ui/never_type/impl_trait_fallback3.stderr +++ b/src/test/ui/never_type/impl_trait_fallback3.stderr @@ -1,10 +1,9 @@ -error: unconstrained opaque type - --> $DIR/impl_trait_fallback3.rs:9:12 +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/impl_trait_fallback3.rs:11:11 | -LL | type Foo = impl T; - | ^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module +LL | fn a() -> Foo { + | ^^^ the trait `T` is not implemented for `()` error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/never-from-impl-is-reserved.stderr b/src/test/ui/never_type/never-from-impl-is-reserved.stderr index 871c512052821..f9f7c787ecbc3 100644 --- a/src/test/ui/never_type/never-from-impl-is-reserved.stderr +++ b/src/test/ui/never_type/never-from-impl-is-reserved.stderr @@ -5,7 +5,7 @@ LL | impl MyTrait for MyFoo {} | ---------------------- first implementation here LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`. LL | impl<T> MyTrait for T where T: From<!> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo` + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo` | = note: permitting this impl would forbid us from adding `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr index a59e553315ae6..5233f0b246261 100644 --- a/src/test/ui/nll/closure-captures.stderr +++ b/src/test/ui/nll/closure-captures.stderr @@ -37,36 +37,32 @@ LL | x = 1; error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:27:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | || - | | ^^ cannot borrow as mutable -LL | | x = 1;} - | |__________-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | || + | ^^ cannot borrow as mutable +LL | x = 1;} + | - mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:31:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | || - | | ^^ cannot borrow as mutable -LL | | x = 1;}); - | |_____-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | || + | ^^ cannot borrow as mutable +LL | x = 1;}); + | - mutable borrow occurs due to use of `x` in closure error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:39:10 @@ -80,19 +76,17 @@ LL | x = 1;} error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:38:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | || - | | ^^ cannot borrow as mutable -LL | | x = 1;} - | |__________-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | || + | ^^ cannot borrow as mutable +LL | x = 1;} + | - mutable borrow occurs due to use of `x` in closure error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/closure-captures.rs:43:5 @@ -106,53 +100,47 @@ LL | x = 1;}); error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:42:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | || - | | ^^ cannot borrow as mutable -LL | | x = 1;}); - | |_____-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | || + | ^^ cannot borrow as mutable +LL | x = 1;}); + | - mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:48:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(|| { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | || - | | ^^ cannot borrow as mutable -LL | | *x = 1;}); - | |_________--_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | || + | ^^ cannot borrow as mutable +LL | *x = 1;}); + | -- mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:51:9 | -LL | fn fn_ref<F: Fn()>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | fn_ref(move || { - | _____------_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | || - | | ^^ cannot borrow as mutable -LL | | *x = 1;}); - | |_________--_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | || + | ^^ cannot borrow as mutable +LL | *x = 1;}); + | -- mutable borrow occurs due to use of `x` in closure error: aborting due to 12 previous errors diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index ff16bf0e078fc..f86a19fff8458 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -2,7 +2,7 @@ note: no external requirements --> $DIR/escape-argument-callee.rs:26:38 | LL | let mut closure = expect_sig(|p, y| *p = y); - | ^^^^^^^^^^^^^ + | ^^^^^^ | = note: defining type: test::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 49ec0dd931ac0..8cd8b43cabec6 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -2,7 +2,7 @@ note: no external requirements --> $DIR/escape-argument.rs:26:38 | LL | let mut closure = expect_sig(|p, y| *p = y); - | ^^^^^^^^^^^^^ + | ^^^^^^ | = note: defining type: test::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index f0ae4c7fb0492..abf80e0392899 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/escape-upvar-nested.rs:21:32 | LL | let mut closure1 = || p = &y; - | ^^^^^^^^^ + | ^^ | = note: defining type: test::{closure#0}::{closure#0} with closure substs [ i16, @@ -15,12 +15,8 @@ LL | let mut closure1 = || p = &y; note: external requirements --> $DIR/escape-upvar-nested.rs:20:27 | -LL | let mut closure = || { - | ___________________________^ -LL | | let mut closure1 = || p = &y; -LL | | closure1(); -LL | | }; - | |_________^ +LL | let mut closure = || { + | ^^ | = note: defining type: test::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index e99fc4b43a23d..bc7546421731a 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/escape-upvar-ref.rs:23:27 | LL | let mut closure = || p = &y; - | ^^^^^^^^^ + | ^^ | = note: defining type: test::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 11420efaa066e..b9b0f3ad25789 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -1,12 +1,8 @@ note: no external requirements --> $DIR/propagate-approximated-fail-no-postdom.rs:43:9 | -LL | / |_outlives1, _outlives2, _outlives3, x, y| { -LL | | // Only works if 'x: 'y: -LL | | let p = x.get(); -LL | | demand_y(x, y, p) -LL | | }, - | |_________^ +LL | |_outlives1, _outlives2, _outlives3, x, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 98c3c28fb43ff..a2371ee314a77 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -1,13 +1,8 @@ note: external requirements --> $DIR/propagate-approximated-ref.rs:43:47 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | _______________________________________________^ -LL | | // Only works if 'x: 'y: -LL | | demand_y(x, y, x.get()) -LL | | -LL | | }); - | |_____^ +LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 3ab55b370c231..e53ae167f12d6 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -1,12 +1,8 @@ note: no external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:21:15 | -LL | foo(cell, |cell_a, cell_x| { - | _______________^ -LL | | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure -LL | | -LL | | }) - | |_____^ +LL | foo(cell, |cell_a, cell_x| { + | ^^^^^^^^^^^^^^^^ | = note: defining type: case1::{closure#0} with closure substs [ i32, @@ -41,11 +37,8 @@ LL | | } note: external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15 | -LL | foo(cell, |cell_a, cell_x| { - | _______________^ -LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error -LL | | }) - | |_____^ +LL | foo(cell, |cell_a, cell_x| { + | ^^^^^^^^^^^^^^^^ | = note: defining type: case2::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index ec2c220b6b8a0..c3c7eb1bd9e5e 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -1,14 +1,8 @@ note: external requirements --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:47 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | _______________________________________________^ -LL | | -LL | | -LL | | // Only works if 'x: 'y: -LL | | demand_y(x, y, x.get()) -LL | | }); - | |_____^ +LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { + | ^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 234212c88767a..846e5aedb3e73 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -1,14 +1,8 @@ note: external requirements --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:47 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | _______________________________________________^ -LL | | -LL | | -LL | | // Only works if 'x: 'y: -LL | | demand_y(x, y, x.get()) -LL | | }); - | |_____^ +LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index 2ec9d4d8db1a6..a570932eda9ad 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -1,13 +1,8 @@ note: external requirements --> $DIR/propagate-approximated-val.rs:36:45 | -LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { - | _____________________________________________^ -LL | | // Only works if 'x: 'y: -LL | | demand_y(outlives1, outlives2, x.get()) -LL | | -LL | | }); - | |_____^ +LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: defining type: test::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 21e4232c788fb..407bc6764d6da 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -1,12 +1,8 @@ note: external requirements --> $DIR/propagate-despite-same-free-region.rs:42:9 | -LL | / |_outlives1, _outlives2, x, y| { -LL | | // Only works if 'x: 'y: -LL | | let p = x.get(); -LL | | demand_y(x, y, p) -LL | | }, - | |_________^ +LL | |_outlives1, _outlives2, x, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 8b9b043542057..fcb55d37f310a 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -1,13 +1,8 @@ note: no external requirements --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:35:47 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | _______________________________________________^ -LL | | // Only works if 'x: 'y: -LL | | demand_y(x, y, x.get()) -LL | | -LL | | }); - | |_____^ +LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { + | ^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 060ce690f0306..75beae39e2310 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -1,13 +1,8 @@ note: no external requirements --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:39:47 | -LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | _______________________________________________^ -LL | | // Only works if 'x: 'y: -LL | | demand_y(x, y, x.get()) -LL | | -LL | | }); - | |_____^ +LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: defining type: supply::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index 08605efa2ea9c..58aced2bfcdb1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -1,15 +1,8 @@ note: external requirements --> $DIR/propagate-from-trait-match.rs:32:36 | -LL | establish_relationships(value, |value| { - | ____________________________________^ -LL | | -LL | | -LL | | // This function call requires that -... | -LL | | require(value); -LL | | }); - | |_____^ +LL | establish_relationships(value, |value| { + | ^^^^^^^ | = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 5fc1d5c436181..1c9d0c835494d 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -2,7 +2,7 @@ note: no external requirements --> $DIR/return-wrong-bound-region.rs:11:16 | LL | expect_sig(|a, b| b); // ought to return `a` - | ^^^^^^^^ + | ^^^^^^ | = note: defining type: test::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs index ebea6d3d9d1ea..46a156d2af9ee 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs +++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs @@ -25,14 +25,12 @@ impl Drop for D { fn cannot_partially_init_adt_with_drop() { let d: D; - d.x = 10; - //~^ ERROR assign of possibly-uninitialized variable: `d` [E0381] + d.x = 10; //~ ERROR E0381 } fn cannot_partially_init_mutable_adt_with_drop() { let mut d: D; - d.x = 10; - //~^ ERROR assign of possibly-uninitialized variable: `d` [E0381] + d.x = 10; //~ ERROR E0381 } fn cannot_partially_reinit_adt_with_drop() { @@ -44,14 +42,12 @@ fn cannot_partially_reinit_adt_with_drop() { fn cannot_partially_init_inner_adt_via_outer_with_drop() { let d: D; - d.s.y = 20; - //~^ ERROR assign to part of possibly-uninitialized variable: `d` [E0381] + d.s.y = 20; //~ ERROR E0381 } fn cannot_partially_init_inner_adt_via_mutable_outer_with_drop() { let mut d: D; - d.s.y = 20; - //~^ ERROR assign to part of possibly-uninitialized variable: `d` [E0381] + d.s.y = 20; //~ ERROR E0381 } fn cannot_partially_reinit_inner_adt_via_outer_with_drop() { diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr index 1b66e034d3785..63f230be7d4b3 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr @@ -1,17 +1,25 @@ -error[E0381]: assign of possibly-uninitialized variable: `d` +error[E0381]: assigned binding `d` isn't fully initialized --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5 | +LL | let d: D; + | - binding declared here but left uninitialized LL | d.x = 10; - | ^^^^^^^^ use of possibly-uninitialized `d` + | ^^^^^^^^ `d` assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign of possibly-uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:34:5 +error[E0381]: assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:33:5 | +LL | let mut d: D; + | ----- binding declared here but left uninitialized LL | d.x = 10; - | ^^^^^^^^ use of possibly-uninitialized `d` + | ^^^^^^^^ `d` assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:41:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:39:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait @@ -20,20 +28,28 @@ LL | drop(d); LL | d.x = 10; | ^^^^^^^^ value assigned here after move -error[E0381]: assign to part of possibly-uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:47:5 +error[E0381]: partially assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5 | +LL | let d: D; + | - binding declared here but left uninitialized LL | d.s.y = 20; - | ^^^^^^^^^^ use of possibly-uninitialized `d.s` + | ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:53:5 +error[E0381]: partially assigned binding `d` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:50:5 | +LL | let mut d: D; + | ----- binding declared here but left uninitialized LL | d.s.y = 20; - | ^^^^^^^^^^ use of possibly-uninitialized `d.s` + | ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `d` - --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:60:5 + --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:56:5 | LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} }; | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-use.rs index 1836f766cc7ef..4cd1e406f9440 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.rs +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.rs @@ -94,15 +94,13 @@ macro_rules! use_part { fn test_0000_local_fully_init_and_use_struct() { let s: S<B>; - s.x = 10; s.y = Box::new(20); - //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381] + s.x = 10; s.y = Box::new(20); //~ ERROR E0381 use_fully!(struct s); } fn test_0001_local_fully_init_and_use_tuple() { let t: T; - t.0 = 10; t.1 = Box::new(20); - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 10; t.1 = Box::new(20); //~ ERROR E0381 use_fully!(tuple t); } @@ -122,15 +120,13 @@ fn test_0011_local_fully_reinit_and_use_tuple() { fn test_0100_local_partial_init_and_use_struct() { let s: S<B>; - s.x = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381] + s.x = 10; //~ ERROR E0381 use_part!(struct s); } fn test_0101_local_partial_init_and_use_tuple() { let t: T; - t.0 = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 10; //~ ERROR E0381 use_part!(tuple t); } @@ -150,15 +146,13 @@ fn test_0111_local_partial_reinit_and_use_tuple() { fn test_0200_local_void_init_and_use_struct() { let s: S<Void>; - s.x = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381] + s.x = 10; //~ ERROR E0381 use_part!(struct s); } fn test_0201_local_void_init_and_use_tuple() { let t: Tvoid; - t.0 = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381] + t.0 = 10; //~ ERROR E0381 use_part!(tuple t); } @@ -173,15 +167,13 @@ fn test_0201_local_void_init_and_use_tuple() { fn test_1000_field_fully_init_and_use_struct() { let q: Q<S<B>>; - q.r.f.x = 10; q.r.f.y = Box::new(20); - //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381] + q.r.f.x = 10; q.r.f.y = Box::new(20); //~ ERROR E0381 use_fully!(struct q.r.f); } fn test_1001_field_fully_init_and_use_tuple() { let q: Q<T>; - q.r.f.0 = 10; q.r.f.1 = Box::new(20); - //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381] + q.r.f.0 = 10; q.r.f.1 = Box::new(20); //~ ERROR E0381 use_fully!(tuple q.r.f); } @@ -201,15 +193,13 @@ fn test_1011_field_fully_reinit_and_use_tuple() { fn test_1100_field_partial_init_and_use_struct() { let q: Q<S<B>>; - q.r.f.x = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381] + q.r.f.x = 10; //~ ERROR E0381 use_part!(struct q.r.f); } fn test_1101_field_partial_init_and_use_tuple() { let q: Q<T>; - q.r.f.0 = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381] + q.r.f.0 = 10; //~ ERROR E0381 use_part!(tuple q.r.f); } @@ -229,15 +219,13 @@ fn test_1111_field_partial_reinit_and_use_tuple() { fn test_1200_field_void_init_and_use_struct() { let mut q: Q<S<Void>>; - q.r.f.x = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381] + q.r.f.x = 10; //~ ERROR E0381 use_part!(struct q.r.f); } fn test_1201_field_void_init_and_use_tuple() { let mut q: Q<Tvoid>; - q.r.f.0 = 10; - //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381] + q.r.f.0 = 10; //~ ERROR E0381 use_part!(tuple q.r.f); } diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr index 77fa484c21d7e..947c9e29b4508 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr @@ -1,17 +1,25 @@ -error[E0381]: assign to part of possibly-uninitialized variable: `s` +error[E0381]: partially assigned binding `s` isn't fully initialized --> $DIR/issue-21232-partial-init-and-use.rs:97:5 | +LL | let s: S<B>; + | - binding declared here but left uninitialized LL | s.x = 10; s.y = Box::new(20); - | ^^^^^^^^ use of possibly-uninitialized `s` + | ^^^^^^^^ `s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:104:5 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:103:5 | +LL | let t: T; + | - binding declared here but left uninitialized LL | t.0 = 10; t.1 = Box::new(20); - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `s` - --> $DIR/issue-21232-partial-init-and-use.rs:111:5 + --> $DIR/issue-21232-partial-init-and-use.rs:109:5 | LL | let mut s: S<B> = S::new(); drop(s); | ----- - value moved here @@ -21,7 +29,7 @@ LL | s.x = 10; s.y = Box::new(20); | ^^^^^^^^ value partially assigned here after move error[E0382]: assign to part of moved value: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:118:5 + --> $DIR/issue-21232-partial-init-and-use.rs:116:5 | LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here @@ -30,20 +38,28 @@ LL | let mut t: T = (0, Box::new(0)); drop(t); LL | t.0 = 10; t.1 = Box::new(20); | ^^^^^^^^ value partially assigned here after move -error[E0381]: assign to part of possibly-uninitialized variable: `s` - --> $DIR/issue-21232-partial-init-and-use.rs:125:5 +error[E0381]: partially assigned binding `s` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:123:5 | +LL | let s: S<B>; + | - binding declared here but left uninitialized LL | s.x = 10; - | ^^^^^^^^ use of possibly-uninitialized `s` + | ^^^^^^^^ `s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:132:5 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:129:5 | +LL | let t: T; + | - binding declared here but left uninitialized LL | t.0 = 10; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `s` - --> $DIR/issue-21232-partial-init-and-use.rs:139:5 + --> $DIR/issue-21232-partial-init-and-use.rs:135:5 | LL | let mut s: S<B> = S::new(); drop(s); | ----- - value moved here @@ -53,7 +69,7 @@ LL | s.x = 10; | ^^^^^^^^ value partially assigned here after move error[E0382]: assign to part of moved value: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:146:5 + --> $DIR/issue-21232-partial-init-and-use.rs:142:5 | LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here @@ -62,32 +78,48 @@ LL | let mut t: T = (0, Box::new(0)); drop(t); LL | t.0 = 10; | ^^^^^^^^ value partially assigned here after move -error[E0381]: assign to part of possibly-uninitialized variable: `s` - --> $DIR/issue-21232-partial-init-and-use.rs:153:5 +error[E0381]: partially assigned binding `s` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:149:5 | +LL | let s: S<Void>; + | - binding declared here but left uninitialized LL | s.x = 10; - | ^^^^^^^^ use of possibly-uninitialized `s` + | ^^^^^^^^ `s` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `t` - --> $DIR/issue-21232-partial-init-and-use.rs:160:5 +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:155:5 | +LL | let t: Tvoid; + | - binding declared here but left uninitialized LL | t.0 = 10; - | ^^^^^^^^ use of possibly-uninitialized `t` + | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `q` - --> $DIR/issue-21232-partial-init-and-use.rs:176:5 +error[E0381]: partially assigned binding `q` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:170:5 | +LL | let q: Q<S<B>>; + | - binding declared here but left uninitialized LL | q.r.f.x = 10; q.r.f.y = Box::new(20); - | ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f` + | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `q` - --> $DIR/issue-21232-partial-init-and-use.rs:183:5 +error[E0381]: partially assigned binding `q` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:176:5 | +LL | let q: Q<T>; + | - binding declared here but left uninitialized LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); - | ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f` + | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:190:5 + --> $DIR/issue-21232-partial-init-and-use.rs:182:5 | LL | let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r); | --- value moved here @@ -97,7 +129,7 @@ LL | q.r.f.x = 10; q.r.f.y = Box::new(20); = note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:197:5 + --> $DIR/issue-21232-partial-init-and-use.rs:189:5 | LL | let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r); | --- value moved here @@ -106,20 +138,28 @@ LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); | = note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait -error[E0381]: assign to part of possibly-uninitialized variable: `q` - --> $DIR/issue-21232-partial-init-and-use.rs:204:5 +error[E0381]: partially assigned binding `q` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:196:5 | +LL | let q: Q<S<B>>; + | - binding declared here but left uninitialized LL | q.r.f.x = 10; - | ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f` + | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `q` - --> $DIR/issue-21232-partial-init-and-use.rs:211:5 +error[E0381]: partially assigned binding `q` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:202:5 | +LL | let q: Q<T>; + | - binding declared here but left uninitialized LL | q.r.f.0 = 10; - | ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f` + | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:218:5 + --> $DIR/issue-21232-partial-init-and-use.rs:208:5 | LL | let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r); | --- value moved here @@ -129,7 +169,7 @@ LL | q.r.f.x = 10; = note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` - --> $DIR/issue-21232-partial-init-and-use.rs:225:5 + --> $DIR/issue-21232-partial-init-and-use.rs:215:5 | LL | let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r); | --- value moved here @@ -138,20 +178,28 @@ LL | q.r.f.0 = 10; | = note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait -error[E0381]: assign to part of possibly-uninitialized variable: `q` - --> $DIR/issue-21232-partial-init-and-use.rs:232:5 +error[E0381]: partially assigned binding `q` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:222:5 | +LL | let mut q: Q<S<Void>>; + | ----- binding declared here but left uninitialized LL | q.r.f.x = 10; - | ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f` + | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` -error[E0381]: assign to part of possibly-uninitialized variable: `q` - --> $DIR/issue-21232-partial-init-and-use.rs:239:5 +error[E0381]: partially assigned binding `q` isn't fully initialized + --> $DIR/issue-21232-partial-init-and-use.rs:228:5 | +LL | let mut q: Q<Tvoid>; + | ----- binding declared here but left uninitialized LL | q.r.f.0 = 10; - | ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f` + | ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized + | + = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit` error[E0382]: assign to part of moved value: `c` - --> $DIR/issue-21232-partial-init-and-use.rs:257:13 + --> $DIR/issue-21232-partial-init-and-use.rs:245:13 | LL | let mut c = (1, "".to_owned()); | ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait @@ -162,7 +210,7 @@ LL | c.0 = 2; | ^^^^^^^ value partially assigned here after move error[E0382]: assign to part of moved value: `c` - --> $DIR/issue-21232-partial-init-and-use.rs:267:13 + --> $DIR/issue-21232-partial-init-and-use.rs:255:13 | LL | let mut c = (1, (1, "".to_owned())); | ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait @@ -173,7 +221,7 @@ LL | (c.1).0 = 2; | ^^^^^^^^^^^ value partially assigned here after move error[E0382]: assign to part of moved value: `c.1` - --> $DIR/issue-21232-partial-init-and-use.rs:275:13 + --> $DIR/issue-21232-partial-init-and-use.rs:263:13 | LL | c2 => { | -- value moved here diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr index c9324f0422cdc..fb61b30f09db2 100644 --- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -4,9 +4,8 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` LL | let x = (vec![22], vec![44]); | - captured outer variable LL | expect_fn(|| drop(x.0)); - | --------^^^- - | | | - | | move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait + | -- ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait + | | | captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/nll/issue-54556-stephaneyfx.stderr b/src/test/ui/nll/issue-54556-stephaneyfx.stderr index a5a0fc415bb37..036a7a0abfdcc 100644 --- a/src/test/ui/nll/issue-54556-stephaneyfx.stderr +++ b/src/test/ui/nll/issue-54556-stephaneyfx.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `stmt` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map<Rows<'_>, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map<Rows<'_>, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:19]>` | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped diff --git a/src/test/ui/nll/issue-55651.rs b/src/test/ui/nll/issue-55651.rs index 46255bf74a138..75ba482717460 100644 --- a/src/test/ui/nll/issue-55651.rs +++ b/src/test/ui/nll/issue-55651.rs @@ -1,27 +1,27 @@ // check-pass -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; struct A; struct B; union U { - a: A, - b: B, + a: ManuallyDrop<A>, + b: ManuallyDrop<B>, } fn main() { unsafe { { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.a = A; + u.a = ManuallyDrop::new(A); let a = u.a; // OK } { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.b = B; + u.b = ManuallyDrop::new(B); let a = u.a; // OK } } diff --git a/src/test/ui/nll/issue-98693.rs b/src/test/ui/nll/issue-98693.rs new file mode 100644 index 0000000000000..18e6ec6304646 --- /dev/null +++ b/src/test/ui/nll/issue-98693.rs @@ -0,0 +1,21 @@ +// Regression test for #98693. +// +// The closure encounters an obligation that `T` must outlive `!U1`, +// a placeholder from universe U1. We were ignoring this placeholder +// when promoting the constraint to the enclosing function, and +// thus incorrectly judging the closure to be safe. + +fn assert_static<T>() +where + for<'a> T: 'a, +{ +} + +fn test<T>() { + || { + //~^ ERROR the parameter type `T` may not live long enough + assert_static::<T>(); + }; +} + +fn main() {} diff --git a/src/test/ui/nll/issue-98693.stderr b/src/test/ui/nll/issue-98693.stderr new file mode 100644 index 0000000000000..31689620c6414 --- /dev/null +++ b/src/test/ui/nll/issue-98693.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue-98693.rs:15:5 + | +LL | / || { +LL | | +LL | | assert_static::<T>(); +LL | | }; + | |_____^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn test<T: 'static>() { + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/nll/match-cfg-fake-edges.rs b/src/test/ui/nll/match-cfg-fake-edges.rs index 2e6d675fb641e..252f7f8ba07cf 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.rs +++ b/src/test/ui/nll/match-cfg-fake-edges.rs @@ -18,7 +18,7 @@ fn guard_may_be_skipped(y: i32) { match y { _ if { x = 2; true } => 1, _ if { - x; //~ ERROR use of possibly-uninitialized variable: `x` + x; //~ ERROR E0381 false } => 2, _ => 3, diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr index 4b3817929fd84..250aa482e5c67 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.stderr +++ b/src/test/ui/nll/match-cfg-fake-edges.stderr @@ -1,8 +1,14 @@ -error[E0381]: use of possibly-uninitialized variable: `x` +error[E0381]: used binding `x` isn't initialized --> $DIR/match-cfg-fake-edges.rs:21:13 | +LL | let x; + | - binding declared here but left uninitialized +... +LL | _ if { x = 2; true } => 1, + | ----- binding initialized here in some conditions +LL | _ if { LL | x; - | ^ use of possibly-uninitialized `x` + | ^ `x` used here but it isn't initialized error[E0382]: use of moved value: `x` --> $DIR/match-cfg-fake-edges.rs:35:13 diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr index 2121b59b02da3..664f36f695cf3 100644 --- a/src/test/ui/nll/match-on-borrowed.stderr +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -33,11 +33,13 @@ LL | match t { LL | x; | - borrow later used here -error[E0381]: use of possibly-uninitialized variable: `n` +error[E0381]: used binding `n` isn't initialized --> $DIR/match-on-borrowed.rs:93:11 | +LL | let n: Never; + | - binding declared here but left uninitialized LL | match n {} - | ^ use of possibly-uninitialized `n` + | ^ `n` used here but it isn't initialized error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr index 42d9f057aaa08..06256ebbc29a3 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -2,14 +2,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { - | -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here + | -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here LL | x | ^ | -help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))` lifetime bound +help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound | -LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) { - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_)) { + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 8fe25181da1a0..feab2476970a1 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/projection-no-regions-closure.rs:25:23 | LL | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -39,7 +39,7 @@ note: external requirements --> $DIR/projection-no-regions-closure.rs:34:23 | LL | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -66,7 +66,7 @@ note: external requirements --> $DIR/projection-no-regions-closure.rs:42:23 | LL | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -103,7 +103,7 @@ note: external requirements --> $DIR/projection-no-regions-closure.rs:52:23 | LL | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index caf2e3c474755..98063bd0a7674 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/projection-one-region-closure.rs:45:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -56,7 +56,7 @@ note: external requirements --> $DIR/projection-one-region-closure.rs:56:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -109,7 +109,7 @@ note: external requirements --> $DIR/projection-one-region-closure.rs:70:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -137,7 +137,7 @@ note: external requirements --> $DIR/projection-one-region-closure.rs:80:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 4eebe682d4fbc..45e61bcbda85e 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:37:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -44,7 +44,7 @@ note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:47:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -85,7 +85,7 @@ note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:60:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -113,7 +113,7 @@ note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:69:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -141,7 +141,7 @@ note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:81:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 46a02598e19bc..f2549205b8120 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -2,7 +2,7 @@ note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:36:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -28,7 +28,7 @@ note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -54,7 +54,7 @@ note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -80,7 +80,7 @@ note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -106,7 +106,7 @@ note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 1ee788b40ab9e..8e1b6fa2e4630 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:38:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -40,7 +40,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, @@ -77,7 +77,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:61:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, @@ -105,7 +105,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:70:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, @@ -133,7 +133,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:79:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, @@ -161,7 +161,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:87:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -203,7 +203,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:97:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, @@ -231,7 +231,7 @@ note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index a4588730b3f87..12c76d198e780 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/ty-param-closure-approximate-lower-bound.rs:24:24 | LL | twice(cell, value, |a, b| invoke(a, b)); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = note: defining type: generic::<T>::{closure#0} with closure substs [ i16, @@ -27,7 +27,7 @@ note: external requirements --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24 | LL | twice(cell, value, |a, b| invoke(a, b)); - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = note: defining type: generic_fail::<T>::{closure#0} with closure substs [ i16, diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 084dd93cb86b9..35741859dffec 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -2,7 +2,7 @@ note: external requirements --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23 | LL | with_signature(x, |y| y) - | ^^^^^ + | ^^^ | = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 11a737ba291f0..0261bc39e7127 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -1,15 +1,8 @@ note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26 | -LL | with_signature(a, b, |x, y| { - | __________________________^ -LL | | -LL | | // -LL | | // See `correct_region`, which explains the point of this -... | -LL | | require(&x, &y) -LL | | }) - | |_____^ +LL | with_signature(a, b, |x, y| { + | ^^^^^^ | = note: defining type: no_region::<T>::{closure#0} with closure substs [ i32, @@ -55,15 +48,8 @@ LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) { note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26 | -LL | with_signature(a, b, |x, y| { - | __________________________^ -LL | | // Key point of this test: -LL | | // -LL | | // The *closure* is being type-checked with all of its free -... | -LL | | require(&x, &y) -LL | | }) - | |_____^ +LL | with_signature(a, b, |x, y| { + | ^^^^^^ | = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -90,13 +76,8 @@ LL | | } note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26 | -LL | with_signature(a, b, |x, y| { - | __________________________^ -LL | | -LL | | // See `correct_region` -LL | | require(&x, &y) -LL | | }) - | |_____^ +LL | with_signature(a, b, |x, y| { + | ^^^^^^ | = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [ i32, @@ -140,12 +121,8 @@ LL | T: 'b + 'a, note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26 | -LL | with_signature(a, b, |x, y| { - | __________________________^ -LL | | // See `correct_region` -LL | | require(&x, &y) -LL | | }) - | |_____^ +LL | with_signature(a, b, |x, y| { + | ^^^^^^ | = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr index 3326fa521fc9c..ee332278c30f5 100644 --- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr +++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr @@ -30,15 +30,14 @@ error[E0597]: `c` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here +LL | let _closure = || { + | - `c` dropped here while still borrowed ... LL | SomeEnum::SomeVariant(Cell::new(&c)), | ----------^^- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'a` -... -LL | }; - | - `c` dropped here while still borrowed error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr index 9664fb9f54831..95bbd62c4fb0d 100644 --- a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr +++ b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr @@ -28,28 +28,28 @@ error[E0597]: `c` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here +LL | let _closure = || { + | - `c` dropped here while still borrowed ... LL | f(&c); | --^^- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'a` -LL | }; - | - `c` dropped here while still borrowed error[E0597]: `c` does not live long enough --> $DIR/adt-tuple-struct-calls.rs:53:11 | LL | let f = SomeStruct::<&'a u32>; | - lifetime `'1` appears in the type of `f` -... +LL | let _closure = || { + | - `c` dropped here while still borrowed +LL | let c = 66; LL | f(&c); | --^^- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'1` -LL | }; - | - `c` dropped here while still borrowed error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/user-annotations/fns.stderr b/src/test/ui/nll/user-annotations/fns.stderr index e0640da39e2b6..bd4d121d56914 100644 --- a/src/test/ui/nll/user-annotations/fns.stderr +++ b/src/test/ui/nll/user-annotations/fns.stderr @@ -28,14 +28,14 @@ error[E0597]: `c` does not live long enough | LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here -... +LL | let _closure = || { + | - `c` dropped here while still borrowed +LL | let c = 66; LL | some_fn::<&'a u32>(&c); | -------------------^^- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'a` -LL | }; - | - `c` dropped here while still borrowed error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/user-annotations/method-call.stderr b/src/test/ui/nll/user-annotations/method-call.stderr index 10447e45a6d42..fcaeb465d140e 100644 --- a/src/test/ui/nll/user-annotations/method-call.stderr +++ b/src/test/ui/nll/user-annotations/method-call.stderr @@ -29,13 +29,14 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... +LL | let _closure = || { + | - `c` dropped here while still borrowed +LL | let c = 66; LL | a.method::<&'a u32>(b, &c); | ------------------------^^- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'a` -LL | }; - | - `c` dropped here while still borrowed error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr index e7851833e93b2..328dde9805aae 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr @@ -29,13 +29,14 @@ error[E0597]: `c` does not live long enough LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) { | -- lifetime `'a` defined here ... +LL | let _closure = || { + | - `c` dropped here while still borrowed +LL | let c = 66; LL | <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); | -------------------------------------------^^- | | | | | borrowed value does not live long enough | argument requires that `c` is borrowed for `'a` -LL | }; - | - `c` dropped here while still borrowed error: aborting due to 3 previous errors diff --git a/src/test/ui/no-capture-arc.stderr b/src/test/ui/no-capture-arc.stderr index 7fa2090e3e614..9ae41e78c227d 100644 --- a/src/test/ui/no-capture-arc.stderr +++ b/src/test/ui/no-capture-arc.stderr @@ -17,7 +17,7 @@ note: deref defined here --> $SRC_DIR/alloc/src/sync.rs:LL:COL | LL | type Target = T; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-reuse-move-arc.stderr b/src/test/ui/no-reuse-move-arc.stderr index bcc4506dc8d1c..564b05854740c 100644 --- a/src/test/ui/no-reuse-move-arc.stderr +++ b/src/test/ui/no-reuse-move-arc.stderr @@ -17,7 +17,7 @@ note: deref defined here --> $SRC_DIR/alloc/src/sync.rs:LL:COL | LL | type Target = T; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr index e4c57c04e7269..249c2fe2fa74e 100644 --- a/src/test/ui/no-send-res-ports.stderr +++ b/src/test/ui/no-send-res-ports.stderr @@ -1,17 +1,12 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely --> $DIR/no-send-res-ports.rs:25:5 | -LL | thread::spawn(move|| { - | _____^^^^^^^^^^^^^_- - | | | - | | `Rc<()>` cannot be sent between threads safely -LL | | -LL | | let y = x; -LL | | println!("{:?}", y); -LL | | }); - | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]` +LL | thread::spawn(move|| { + | ^^^^^^^^^^^^^ ------ within this `[closure@$DIR/no-send-res-ports.rs:25:19: 25:25]` + | | + | `Rc<()>` cannot be sent between threads safely | - = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`, the trait `Send` is not implemented for `Rc<()>` + = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 25:25]`, the trait `Send` is not implemented for `Rc<()>` note: required because it appears within the type `Port<()>` --> $DIR/no-send-res-ports.rs:5:8 | @@ -25,13 +20,8 @@ LL | struct Foo { note: required because it's used within this closure --> $DIR/no-send-res-ports.rs:25:19 | -LL | thread::spawn(move|| { - | ___________________^ -LL | | -LL | | let y = x; -LL | | println!("{:?}", y); -LL | | }); - | |_____^ +LL | thread::spawn(move|| { + | ^^^^^^ note: required by a bound in `spawn` --> $SRC_DIR/std/src/thread/mod.rs:LL:COL | diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 4da97ed5d60eb..6e4434e6f3372 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -73,9 +73,9 @@ warning: panic message is not a string literal LL | assert!(false, S); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", S); | +++++ @@ -86,9 +86,9 @@ warning: panic message is not a string literal LL | assert!(false, 123); | ^^^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", 123); | +++++ @@ -99,9 +99,9 @@ warning: panic message is not a string literal LL | assert!(false, Some(123)); | ^^^^^^^^^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{:?}" format string to use the Debug implementation of `Option<i32>` +help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>` | LL | assert!(false, "{:?}", Some(123)); | +++++++ @@ -124,9 +124,9 @@ warning: panic message is not a string literal LL | panic!(C); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", C); | +++++ @@ -137,9 +137,9 @@ warning: panic message is not a string literal LL | panic!(S); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", S); | +++++ @@ -150,9 +150,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); | +++++ @@ -163,9 +163,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); | +++++ @@ -176,9 +176,9 @@ warning: panic message is not a string literal LL | std::panic!(123); | ^^^ | - = note: this usage of std::panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | std::panic!("{}", 123); | +++++ @@ -193,9 +193,9 @@ warning: panic message is not a string literal LL | core::panic!(&*"abc"); | ^^^^^^^ | - = note: this usage of core::panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | core::panic!("{}", &*"abc"); | +++++ @@ -206,9 +206,9 @@ warning: panic message is not a string literal LL | panic!(Some(123)); | ^^^^^^^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{:?}" format string to use the Debug implementation of `Option<i32>` +help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>` | LL | panic!("{:?}", Some(123)); | +++++++ @@ -259,9 +259,9 @@ warning: panic message is not a string literal LL | panic!(a!()); | ^^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", a!()); | +++++ @@ -276,9 +276,9 @@ warning: panic message is not a string literal LL | unreachable!(a!()); | ^^^^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", a!()); | +++++ @@ -289,9 +289,9 @@ warning: panic message is not a string literal LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> - = note: the panic!() macro supports formatting, so there's no need for the format!() macro here + = note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - panic!(format!("{}", 1)); @@ -304,9 +304,9 @@ warning: panic message is not a string literal LL | unreachable!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> - = note: the unreachable!() macro supports formatting, so there's no need for the format!() macro here + = note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - unreachable!(format!("{}", 1)); @@ -319,9 +319,9 @@ warning: panic message is not a string literal LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> - = note: the assert!() macro supports formatting, so there's no need for the format!() macro here + = note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - assert!(false, format!("{}", 1)); @@ -334,9 +334,9 @@ warning: panic message is not a string literal LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of debug_assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> - = note: the debug_assert!() macro supports formatting, so there's no need for the format!() macro here + = note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - debug_assert!(false, format!("{}", 1)); @@ -349,9 +349,9 @@ warning: panic message is not a string literal LL | panic![123]; | ^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!["{}", 123]; | +++++ @@ -366,9 +366,9 @@ warning: panic message is not a string literal LL | panic!{123}; | ^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!{"{}", 123}; | +++++ @@ -385,7 +385,7 @@ LL | panic!(v); | | | help: use std::panic::panic_any instead: `std::panic::panic_any` | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> warning: panic message is not a string literal @@ -394,7 +394,7 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> warning: panic message is not a string literal @@ -403,9 +403,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{:?}" format string to use the Debug implementation of `T` +help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | panic!("{:?}", v); | +++++++ @@ -420,9 +420,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{:?}" format string to use the Debug implementation of `T` +help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | assert!(false, "{:?}", v); | +++++++ @@ -433,9 +433,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); | +++++ @@ -450,9 +450,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); | +++++ @@ -463,9 +463,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); | +++++ @@ -480,9 +480,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); | +++++ diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index 4674c16eb433a..0c696163a26c5 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `Foo` in the current scop --> $DIR/noncopyable-class.rs:34:16 | LL | struct Foo { - | ---------- method `clone` not found for this + | ---------- method `clone` not found for this struct ... LL | let _y = x.clone(); | ^^^^^ method not found in `Foo` diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index bebf561b120b5..37d94cf0ebd8c 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -1,23 +1,17 @@ -error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` +error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]` --> $DIR/not-clone-closure.rs:11:23 | -LL | let hello = move || { - | _________________- -LL | | println!("Hello {}", a.0); -LL | | }; - | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` -LL | -LL | let hello = hello.clone(); - | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`, the trait `Clone` is not implemented for `S` +LL | let hello = move || { + | ------- within this `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]` +... +LL | let hello = hello.clone(); + | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`, the trait `Clone` is not implemented for `S` | note: required because it's used within this closure --> $DIR/not-clone-closure.rs:7:17 | -LL | let hello = move || { - | _________________^ -LL | | println!("Hello {}", a.0); -LL | | }; - | |_____^ +LL | let hello = move || { + | ^^^^^^^ help: consider annotating `S` with `#[derive(Clone)]` | LL | #[derive(Clone)] diff --git a/src/test/ui/numbers-arithmetic/promoted_overflow.rs b/src/test/ui/numbers-arithmetic/promoted_overflow.rs index da59e81ed6bf7..ba168f773d856 100644 --- a/src/test/ui/numbers-arithmetic/promoted_overflow.rs +++ b/src/test/ui/numbers-arithmetic/promoted_overflow.rs @@ -3,6 +3,10 @@ // run-fail // error-pattern: overflow // compile-flags: -C overflow-checks=yes +// for some reason, fails to match error string on +// wasm32-unknown-unknown with stripped debuginfo and symbols, +// so don't strip it +// compile-flags:-Cstrip=none fn main() { let x: &'static u32 = &(0u32 - 1); diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.rs b/src/test/ui/object-safety/object-safety-by-value-self-use.rs index f903f26c0901d..8e93c538217bb 100644 --- a/src/test/ui/object-safety/object-safety-by-value-self-use.rs +++ b/src/test/ui/object-safety/object-safety-by-value-self-use.rs @@ -12,7 +12,7 @@ trait Baz { } fn use_bar(t: Box<dyn Bar>) { - t.bar() //~ ERROR cannot move a value of type dyn Bar + t.bar() //~ ERROR cannot move a value of type `dyn Bar` } fn main() { } diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr index 7ccc0cbdd576b..94fdcdf263ae0 100644 --- a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr +++ b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr @@ -1,8 +1,8 @@ -error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined +error[E0161]: cannot move a value of type `dyn Bar` --> $DIR/object-safety-by-value-self-use.rs:15:5 | LL | t.bar() - | ^^^^^^^ + | ^^^^^^^ the size of `dyn Bar` cannot be statically determined error: aborting due to previous error diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index c94adfe4ab38a..920720a4f53e2 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -38,14 +38,8 @@ LL | enum E { A, B } note: the following trait must be implemented --> $SRC_DIR/core/src/ops/bit.rs:LL:COL | -LL | / pub trait BitOr<Rhs = Self> { -LL | | /// The resulting type after applying the `|` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn bitor(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait BitOr<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/panic-runtime/auxiliary/needs-abort.rs b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs new file mode 100644 index 0000000000000..8fad49b5e9d32 --- /dev/null +++ b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs @@ -0,0 +1,5 @@ +// compile-flags:-C panic=abort +// no-prefer-dynamic + +#![crate_type = "rlib"] +#![no_std] diff --git a/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs new file mode 100644 index 0000000000000..d555b531986b0 --- /dev/null +++ b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs @@ -0,0 +1,13 @@ +// compile-flags:-C panic=unwind +// no-prefer-dynamic + +#![crate_type = "rlib"] +#![no_std] +#![feature(c_unwind)] + +extern "C-unwind" fn foo() {} + +fn bar() { + let ptr: extern "C-unwind" fn() = foo; + ptr(); +} diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.rs b/src/test/ui/panic-runtime/need-abort-got-unwind.rs new file mode 100644 index 0000000000000..c72fb96e357f0 --- /dev/null +++ b/src/test/ui/panic-runtime/need-abort-got-unwind.rs @@ -0,0 +1,9 @@ +// build-fail +// needs-unwind +// error-pattern:is incompatible with this crate's strategy of `unwind` +// aux-build:needs-abort.rs +// ignore-wasm32-bare compiled with panic=abort by default + +extern crate needs_abort; + +fn main() {} diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.stderr b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr new file mode 100644 index 0000000000000..d29c7875fd0ff --- /dev/null +++ b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind` + +error: aborting due to previous error + diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.rs b/src/test/ui/panic-runtime/need-unwind-got-abort.rs new file mode 100644 index 0000000000000..6752ecf90d2f7 --- /dev/null +++ b/src/test/ui/panic-runtime/need-unwind-got-abort.rs @@ -0,0 +1,9 @@ +// build-fail +// error-pattern:is incompatible with this crate's strategy of `abort` +// aux-build:needs-unwind.rs +// compile-flags:-C panic=abort +// no-prefer-dynamic + +extern crate needs_unwind; + +fn main() {} diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.stderr b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr new file mode 100644 index 0000000000000..4c71df3ebc147 --- /dev/null +++ b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` + +error: aborting due to previous error + diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr index 4af754c81f97c..7f4a8ed290ecf 100644 --- a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr +++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr @@ -2,9 +2,7 @@ error: cannot link together two panic runtimes: panic_runtime_unwind and panic_r error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind` -error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` +error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind` -error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs index c48caaf079077..23bfea6af15c1 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs +++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs @@ -1,6 +1,6 @@ // build-fail // needs-unwind -// error-pattern:is incompatible with this crate's strategy of `unwind` +// error-pattern:is not compiled with this crate's panic strategy `unwind` // aux-build:panic-runtime-abort.rs // aux-build:panic-runtime-lang-items.rs // ignore-wasm32-bare compiled with panic=abort by default diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr index d4fd2cca81fdc..d306ce6c5ea28 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr +++ b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr @@ -1,6 +1,4 @@ error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind` -error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr index 364a27a24eb70..014437b7f1b66 100644 --- a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr +++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr @@ -1,8 +1,6 @@ error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind` -error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` +error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind` -error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/panics/issue-47429-short-backtraces.legacy.run.stderr b/src/test/ui/panics/issue-47429-short-backtraces.legacy.run.stderr index fcdc070a4c39e..b6223b93764f4 100644 --- a/src/test/ui/panics/issue-47429-short-backtraces.legacy.run.stderr +++ b/src/test/ui/panics/issue-47429-short-backtraces.legacy.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:21:5 +thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:22:5 stack backtrace: 0: std::panicking::begin_panic 1: issue_47429_short_backtraces::main diff --git a/src/test/ui/panics/issue-47429-short-backtraces.rs b/src/test/ui/panics/issue-47429-short-backtraces.rs index c34e00bab7cdd..f338ace6bb0d1 100644 --- a/src/test/ui/panics/issue-47429-short-backtraces.rs +++ b/src/test/ui/panics/issue-47429-short-backtraces.rs @@ -1,6 +1,7 @@ // Regression test for #47429: short backtraces were not terminating correctly // compile-flags: -O +// compile-flags:-Cstrip=none // run-fail // check-run-results // exec-env:RUST_BACKTRACE=1 diff --git a/src/test/ui/panics/issue-47429-short-backtraces.v0.run.stderr b/src/test/ui/panics/issue-47429-short-backtraces.v0.run.stderr index 1cbf11739bfc6..c2bea44924983 100644 --- a/src/test/ui/panics/issue-47429-short-backtraces.v0.run.stderr +++ b/src/test/ui/panics/issue-47429-short-backtraces.v0.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:21:5 +thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:22:5 stack backtrace: 0: std::panicking::begin_panic::<&str> 1: issue_47429_short_backtraces::main diff --git a/src/test/ui/panics/location-detail-unwrap-no-file.rs b/src/test/ui/panics/location-detail-unwrap-no-file.rs index 16cf8a17ff190..5955d9a25ae73 100644 --- a/src/test/ui/panics/location-detail-unwrap-no-file.rs +++ b/src/test/ui/panics/location-detail-unwrap-no-file.rs @@ -1,6 +1,6 @@ // run-fail // check-run-results -// compile-flags: -Zlocation-detail=line,column +// compile-flags: -Copt-level=0 -Zlocation-detail=line,column // exec-env:RUST_BACKTRACE=0 fn main() { diff --git a/src/test/ui/panics/runtime-switch.legacy.run.stderr b/src/test/ui/panics/runtime-switch.legacy.run.stderr index 979cc56b8312e..f282f18839c64 100644 --- a/src/test/ui/panics/runtime-switch.legacy.run.stderr +++ b/src/test/ui/panics/runtime-switch.legacy.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/runtime-switch.rs:24:5 +thread 'main' panicked at 'explicit panic', $DIR/runtime-switch.rs:25:5 stack backtrace: 0: std::panicking::begin_panic 1: runtime_switch::main diff --git a/src/test/ui/panics/runtime-switch.rs b/src/test/ui/panics/runtime-switch.rs index c163481140666..37ef961e2d019 100644 --- a/src/test/ui/panics/runtime-switch.rs +++ b/src/test/ui/panics/runtime-switch.rs @@ -1,6 +1,7 @@ // Test for std::panic::set_backtrace_style. // compile-flags: -O +// compile-flags:-Cstrip=none // run-fail // check-run-results // exec-env:RUST_BACKTRACE=0 diff --git a/src/test/ui/panics/runtime-switch.v0.run.stderr b/src/test/ui/panics/runtime-switch.v0.run.stderr index 48f829c26d445..7ce9722e5edf1 100644 --- a/src/test/ui/panics/runtime-switch.v0.run.stderr +++ b/src/test/ui/panics/runtime-switch.v0.run.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/runtime-switch.rs:24:5 +thread 'main' panicked at 'explicit panic', $DIR/runtime-switch.rs:25:5 stack backtrace: 0: std::panicking::begin_panic::<&str> 1: runtime_switch::main diff --git a/src/test/ui/panics/unique-panic.rs b/src/test/ui/panics/unique-panic.rs index 22e0d63d5946f..ae7911e594389 100644 --- a/src/test/ui/panics/unique-panic.rs +++ b/src/test/ui/panics/unique-panic.rs @@ -1,5 +1,9 @@ // run-fail // error-pattern: panic +// for some reason, fails to match error string on +// wasm32-unknown-unknown with stripped debuginfo and symbols, +// so don't strip it +// compile-flags:-Cstrip=none fn main() { Box::new(panic!()); diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr index 7dc589e556386..2550dc3d321d8 100644 --- a/src/test/ui/parser/emoji-identifiers.stderr +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -77,7 +77,7 @@ error[E0599]: no function or associated item named `full_of✨` found for struct --> $DIR/emoji-identifiers.rs:9:8 | LL | struct 👀; - | ---------- function or associated item `full_of✨` not found for this + | --------- function or associated item `full_of✨` not found for this struct ... LL | 👀::full_of✨() | ^^^^^^^^^ diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr index d4f64a7de5bcf..858b4e8db0547 100644 --- a/src/test/ui/parser/expr-as-stmt.stderr +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -200,7 +200,7 @@ LL | { true } || { true } | ^^^^^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:25]` + found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:16]` help: use parentheses to call this closure | LL | { true } (|| { true })() diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index bd3b9181123bb..75d27c614e202 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -234,30 +234,30 @@ LL | const async unsafe extern "C" fn ft5(); LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future` -error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5::{opaque#0}` +error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}` --> $DIR/fn-header-semantic-fail.rs:34:48 | LL | const async unsafe extern "C" fn ft5() {} | ^ | -note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5`... +note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`... --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5`... +note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`... --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5`... +note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5`... --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze... = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`... - = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 40:6>::ft5::{opaque#0}`, completing the cycle + = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/fn-header-semantic-fail.rs:5:1 | @@ -270,30 +270,30 @@ LL | | } LL | | } | |_^ -error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5::{opaque#0}` +error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5::{opaque#0}` --> $DIR/fn-header-semantic-fail.rs:47:48 | LL | const async unsafe extern "C" fn fi5() {} | ^ | -note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5`... +note: ...which requires borrow-checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5`... --> $DIR/fn-header-semantic-fail.rs:47:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5`... +note: ...which requires processing `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5`... --> $DIR/fn-header-semantic-fail.rs:47:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5`... +note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5`... --> $DIR/fn-header-semantic-fail.rs:47:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze... = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`... - = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 50:6>::fi5::{opaque#0}`, completing the cycle + = note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:42:5: 42:11>::fi5::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/fn-header-semantic-fail.rs:5:1 | diff --git a/src/test/ui/parser/issues/issue-52496.stderr b/src/test/ui/parser/issues/issue-52496.stderr index 9dbf26ef4b68c..77335c64c2120 100644 --- a/src/test/ui/parser/issues/issue-52496.stderr +++ b/src/test/ui/parser/issues/issue-52496.stderr @@ -4,12 +4,13 @@ error: float literals must have an integer part LL | let _ = Foo { bar: .5, baz: 42 }; | ^^ help: must have an integer part: `0.5` -error: expected one of `,` or `}`, found `.` +error: expected one of `,`, `:`, or `}`, found `.` --> $DIR/issue-52496.rs:8:22 | LL | let _ = Foo { bar.into(), bat: -1, . }; - | --- ^ expected one of `,` or `}` - | | + | --- - ^ expected one of `,`, `:`, or `}` + | | | + | | help: try naming a field: `bar:` | while parsing this struct error: expected identifier, found `.` diff --git a/src/test/ui/parser/issues/issue-62973.stderr b/src/test/ui/parser/issues/issue-62973.stderr index bc3358fc6baa6..4737bc71860c2 100644 --- a/src/test/ui/parser/issues/issue-62973.stderr +++ b/src/test/ui/parser/issues/issue-62973.stderr @@ -20,15 +20,23 @@ LL | LL | | ^ -error: expected one of `,` or `}`, found `{` +error: expected one of `,`, `:`, or `}`, found `{` --> $DIR/issue-62973.rs:6:8 | LL | fn p() { match s { v, E { [) {) } - | ^ - -^ expected one of `,` or `}` - | | | | - | | | help: `}` may belong here + | ^ - ^ expected one of `,`, `:`, or `}` + | | | | | while parsing this struct | unclosed delimiter + | +help: `}` may belong here + | +LL | fn p() { match s { v, E} { [) {) } + | + +help: try naming a field + | +LL | fn p() { match s { v, E: E { [) {) } + | ++ error: struct literals are not allowed here --> $DIR/issue-62973.rs:6:16 diff --git a/src/test/ui/parser/macro/macro-doc-comments-1.stderr b/src/test/ui/parser/macro/macro-doc-comments-1.stderr index 96bdb9808eefd..0ebf3d52b6372 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-1.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-1.stderr @@ -5,7 +5,10 @@ LL | macro_rules! outer { | ------------------ when calling this macro ... LL | //! Inner - | ^^^^^^^^^ no rules expected this token in macro call + | ^^^^^^^^^ + | | + | no rules expected this token in macro call + | inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match error: aborting due to previous error diff --git a/src/test/ui/parser/macro/macro-doc-comments-2.stderr b/src/test/ui/parser/macro/macro-doc-comments-2.stderr index 023d1a3e039f8..346d865868d99 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-2.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-2.stderr @@ -5,7 +5,10 @@ LL | macro_rules! inner { | ------------------ when calling this macro ... LL | /// Outer - | ^^^^^^^^^ no rules expected this token in macro call + | ^^^^^^^^^ + | | + | no rules expected this token in macro call + | outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match error: aborting due to previous error diff --git a/src/test/ui/parser/recover-quantified-closure.rs b/src/test/ui/parser/recover-quantified-closure.rs index 381324738f62b..10af39b700748 100644 --- a/src/test/ui/parser/recover-quantified-closure.rs +++ b/src/test/ui/parser/recover-quantified-closure.rs @@ -1,10 +1,12 @@ fn main() { for<'a> |x: &'a u8| *x + 1; - //~^ ERROR cannot introduce explicit parameters for a closure + //~^ ERROR `for<...>` binders for closures are experimental + //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present } enum Foo { Bar } fn foo(x: impl Iterator<Item = Foo>) { for <Foo>::Bar in x {} //~^ ERROR expected one of `move`, `static`, `|` + //~^^ ERROR `for<...>` binders for closures are experimental } diff --git a/src/test/ui/parser/recover-quantified-closure.stderr b/src/test/ui/parser/recover-quantified-closure.stderr index 0f01132651648..39eec80f658ad 100644 --- a/src/test/ui/parser/recover-quantified-closure.stderr +++ b/src/test/ui/parser/recover-quantified-closure.stderr @@ -1,16 +1,37 @@ -error: cannot introduce explicit parameters for a closure +error: expected one of `move`, `static`, `|`, or `||`, found `::` + --> $DIR/recover-quantified-closure.rs:9:14 + | +LL | for <Foo>::Bar in x {} + | ^^ expected one of `move`, `static`, `|`, or `||` + +error[E0658]: `for<...>` binders for closures are experimental --> $DIR/recover-quantified-closure.rs:2:5 | LL | for<'a> |x: &'a u8| *x + 1; - | ^^^^^^^ ------------------ the parameters are attached to this closure - | | - | help: remove the parameters + | ^^^^^^^ + | + = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = help: consider removing `for<...>` -error: expected one of `move`, `static`, `|`, or `||`, found `::` - --> $DIR/recover-quantified-closure.rs:8:14 +error[E0658]: `for<...>` binders for closures are experimental + --> $DIR/recover-quantified-closure.rs:9:5 | LL | for <Foo>::Bar in x {} - | ^^ expected one of `move`, `static`, `|`, or `||` + | ^^^^^^^^^ + | + = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information + = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable + = help: consider removing `for<...>` + +error: implicit types in closure signatures are forbidden when `for<...>` is present + --> $DIR/recover-quantified-closure.rs:2:25 + | +LL | for<'a> |x: &'a u8| *x + 1; + | ------- ^ + | | + | `for<...>` is here -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/removed-syntax-with-2.rs b/src/test/ui/parser/removed-syntax-with-2.rs index 8a489e71990fb..451057c66a127 100644 --- a/src/test/ui/parser/removed-syntax-with-2.rs +++ b/src/test/ui/parser/removed-syntax-with-2.rs @@ -6,6 +6,6 @@ fn main() { let a = S { foo: (), bar: () }; let b = S { foo: (), with a }; - //~^ ERROR expected one of `,` or `}`, found `a` + //~^ ERROR expected one of `,`, `:`, or `}`, found `a` //~| ERROR missing field `bar` in initializer of `S` } diff --git a/src/test/ui/parser/removed-syntax-with-2.stderr b/src/test/ui/parser/removed-syntax-with-2.stderr index 2c96dceb587ec..c6ae1ce674ff8 100644 --- a/src/test/ui/parser/removed-syntax-with-2.stderr +++ b/src/test/ui/parser/removed-syntax-with-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `}`, found `a` +error: expected one of `,`, `:`, or `}`, found `a` --> $DIR/removed-syntax-with-2.rs:8:31 | LL | let b = S { foo: (), with a }; - | - ^ expected one of `,` or `}` + | - ^ expected one of `,`, `:`, or `}` | | | while parsing this struct diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr index e71f15ebfd2e7..0852c7cb4705d 100644 --- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr +++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr @@ -24,7 +24,7 @@ LL | | }.hi() { | |__________^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]` + found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 12:13]` help: use parentheses to call this closure | LL ~ while (|| Foo { diff --git a/src/test/ui/pattern/for-loop-bad-item.stderr b/src/test/ui/pattern/for-loop-bad-item.stderr index ad737f7bd15e1..f064a25a9c9a4 100644 --- a/src/test/ui/pattern/for-loop-bad-item.stderr +++ b/src/test/ui/pattern/for-loop-bad-item.stderr @@ -8,6 +8,11 @@ LL | for ((_, _), (&mut c, _)) in &mut map { | = note: expected type `char` found mutable reference `&mut _` +note: to declare a mutable binding use: `mut c` + --> $DIR/for-loop-bad-item.rs:7:19 + | +LL | for ((_, _), (&mut c, _)) in &mut map { + | ^^^^^^ help: consider removing `&mut` from the pattern | LL - for ((_, _), (&mut c, _)) in &mut map { diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr index 06a279925edbc..8e528f8c1db94 100644 --- a/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr @@ -12,8 +12,6 @@ error[E0282]: type annotations needed | LL | Zero::ZERO ..= Zero::ZERO => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type - | - = note: type must be known at this point error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/non-structural-match-types.stderr b/src/test/ui/pattern/non-structural-match-types.stderr index e9b56cdc05d01..45e1626497388 100644 --- a/src/test/ui/pattern/non-structural-match-types.stderr +++ b/src/test/ui/pattern/non-structural-match-types.stderr @@ -1,4 +1,4 @@ -error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used in patterns +error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:19]` cannot be used in patterns --> $DIR/non-structural-match-types.rs:9:9 | LL | const { || {} } => {}, diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index 11b28987848d6..3342b8e4002b9 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -3,8 +3,10 @@ error[E0282]: type annotations needed | LL | let x; | ^ +... +LL | (..) => {} + | ---- type must be known at this point | - = note: type must be known at this point help: consider giving `x` an explicit type | LL | let x: _; diff --git a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr index 07b678bc8731a..d9295746158bb 100644 --- a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr +++ b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr @@ -5,7 +5,10 @@ LL | use declarations_for_tuple_field_count_errors::*; | -------------------------------------------- the tuple struct `Z1` is imported here ... LL | Z1 => {} - | ^^ cannot be named the same as a tuple struct + | ^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `Z1(..)` error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` --> $DIR/pat-tuple-field-count-cross.rs:9:9 @@ -16,9 +19,9 @@ LL | Z0() => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:1:1 | LL | pub struct Z0; - | -------------- `Z0` defined here + | ------------- `Z0` defined here LL | pub struct Z1(); - | ---------------- similarly named tuple struct `Z1` defined here + | ------------- similarly named tuple struct `Z1` defined here | help: use this syntax instead | @@ -38,9 +41,9 @@ LL | Z0(x) => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:1:1 | LL | pub struct Z0; - | -------------- `Z0` defined here + | ------------- `Z0` defined here LL | pub struct Z1(); - | ---------------- similarly named tuple struct `Z1` defined here + | ------------- similarly named tuple struct `Z1` defined here | help: use this syntax instead | @@ -60,7 +63,7 @@ LL | E1::Z0() => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15 | LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } - | -- ---- similarly named tuple variant `Z1` defined here + | -- -- similarly named tuple variant `Z1` defined here | | | `E1::Z0` defined here | @@ -82,7 +85,7 @@ LL | E1::Z0(x) => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15 | LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } - | -- ---- similarly named tuple variant `Z1` defined here + | -- -- similarly named tuple variant `Z1` defined here | | | `E1::Z0` defined here | @@ -104,7 +107,7 @@ LL | E1::Z1 => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19 | LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } - | -- ---- `E1::Z1` defined here + | -- -- `E1::Z1` defined here | | | similarly named unit variant `Z0` defined here | @@ -126,7 +129,7 @@ LL | Z1(x) => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:2:1 | LL | pub struct Z1(); - | ---------------- tuple struct has 0 fields + | ------------- tuple struct has 0 fields error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:18:9 @@ -295,7 +298,7 @@ LL | E1::Z1(x) => {} ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19 | LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } - | ---- tuple variant has 0 fields + | -- tuple variant has 0 fields error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields --> $DIR/pat-tuple-field-count-cross.rs:39:9 diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr index 1c44f7e5f6f1f..54d89e03101dc 100644 --- a/src/test/ui/pattern/pat-tuple-overfield.stderr +++ b/src/test/ui/pattern/pat-tuple-overfield.stderr @@ -5,7 +5,10 @@ LL | struct Z1(); | ------------ the tuple struct `Z1` is defined here ... LL | Z1 => {} - | ^^ cannot be named the same as a tuple struct + | ^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `Z1(..)` error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0` --> $DIR/pat-tuple-overfield.rs:52:9 @@ -271,7 +274,7 @@ error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 0 --> $DIR/pat-tuple-overfield.rs:59:12 | LL | struct Z1(); - | ------------ tuple struct has 0 fields + | --------- tuple struct has 0 fields ... LL | Z1(_) => {} | ^ expected 0 fields, found 1 @@ -280,7 +283,7 @@ error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has --> $DIR/pat-tuple-overfield.rs:60:12 | LL | struct Z1(); - | ------------ tuple struct has 0 fields + | --------- tuple struct has 0 fields ... LL | Z1(_, _) => {} | ^ ^ expected 0 fields, found 2 @@ -289,7 +292,7 @@ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has --> $DIR/pat-tuple-overfield.rs:71:16 | LL | Z1(), - | ---- tuple variant has 0 fields + | -- tuple variant has 0 fields ... LL | E1::Z1(_) => {} | ^ expected 0 fields, found 1 @@ -298,7 +301,7 @@ error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has --> $DIR/pat-tuple-overfield.rs:72:16 | LL | Z1(), - | ---- tuple variant has 0 fields + | -- tuple variant has 0 fields ... LL | E1::Z1(_, _) => {} | ^ ^ expected 0 fields, found 2 diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.stderr b/src/test/ui/pattern/pattern-binding-disambiguation.stderr index faa0d7c30743b..1529e538b5521 100644 --- a/src/test/ui/pattern/pattern-binding-disambiguation.stderr +++ b/src/test/ui/pattern/pattern-binding-disambiguation.stderr @@ -5,7 +5,10 @@ LL | struct TupleStruct(); | --------------------- the tuple struct `TupleStruct` is defined here ... LL | TupleStruct => {} - | ^^^^^^^^^^^ cannot be named the same as a tuple struct + | ^^^^^^^^^^^ + | | + | cannot be named the same as a tuple struct + | help: try specify the pattern arguments: `TupleStruct(..)` error[E0530]: match bindings cannot shadow tuple variants --> $DIR/pattern-binding-disambiguation.rs:33:9 @@ -14,7 +17,10 @@ LL | use E::*; | ---- the tuple variant `TupleVariant` is imported here ... LL | TupleVariant => {} - | ^^^^^^^^^^^^ cannot be named the same as a tuple variant + | ^^^^^^^^^^^^ + | | + | cannot be named the same as a tuple variant + | help: try specify the pattern arguments: `TupleVariant(..)` error[E0530]: match bindings cannot shadow struct variants --> $DIR/pattern-binding-disambiguation.rs:36:9 diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr index 296465eb81838..643e734f9d4fa 100644 --- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr +++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr @@ -7,13 +7,8 @@ LL | match HiddenEnum::A { note: `HiddenEnum` defined here --> $DIR/auxiliary/hidden.rs:1:1 | -LL | / pub enum HiddenEnum { -LL | | A, -LL | | B, -LL | | #[doc(hidden)] -LL | | C, -LL | | } - | |_^ +LL | pub enum HiddenEnum { + | ^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -30,14 +25,11 @@ LL | match HiddenEnum::A { note: `HiddenEnum` defined here --> $DIR/auxiliary/hidden.rs:3:5 | -LL | / pub enum HiddenEnum { -LL | | A, -LL | | B, - | | ^ not covered -LL | | #[doc(hidden)] -LL | | C, -LL | | } - | |_- +LL | pub enum HiddenEnum { + | ------------------- +LL | A, +LL | B, + | ^ not covered = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -54,14 +46,11 @@ LL | match HiddenEnum::A { note: `HiddenEnum` defined here --> $DIR/auxiliary/hidden.rs:3:5 | -LL | / pub enum HiddenEnum { -LL | | A, -LL | | B, - | | ^ not covered -LL | | #[doc(hidden)] -LL | | C, -LL | | } - | |_- +LL | pub enum HiddenEnum { + | ------------------- +LL | A, +LL | B, + | ^ not covered = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -78,15 +67,11 @@ LL | match None { note: `Option<HiddenEnum>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), - | | ^^^^ not covered -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered = note: the matched value is of type `Option<HiddenEnum>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr index 717bb53c32750..2247b818d4385 100644 --- a/src/test/ui/pattern/usefulness/issue-35609.stderr +++ b/src/test/ui/pattern/usefulness/issue-35609.stderr @@ -108,14 +108,8 @@ LL | match Some(A) { note: `Option<Enum>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), -LL | | } - | |_^ +LL | pub enum Option<T> { + | ^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `Option<Enum>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | diff --git a/src/test/ui/pattern/usefulness/issue-3601.stderr b/src/test/ui/pattern/usefulness/issue-3601.stderr index 4e0adcc1ba2a5..eb8c63919b644 100644 --- a/src/test/ui/pattern/usefulness/issue-3601.stderr +++ b/src/test/ui/pattern/usefulness/issue-3601.stderr @@ -11,7 +11,7 @@ LL | / pub struct Box< LL | | T: ?Sized, LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique<T>, A); - | |________________^ + | |_^ = note: the matched value is of type `Box<ElementKind>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr index 3326e6b85a471..a2b66f5ed6752 100644 --- a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -20,18 +20,14 @@ LL | match Some(Some(North)) { note: `Option<Option<Direction>>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), - | | ^^^^ - | | | - | | not covered - | | not covered -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ + | | + | not covered + | not covered = note: the matched value is of type `Option<Option<Direction>>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr index 88178d6429197..4607cfaae1719 100644 --- a/src/test/ui/pattern/usefulness/match-privately-empty.stderr +++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr @@ -7,15 +7,11 @@ LL | match private::DATA { note: `Option<Private>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), - | | ^^^^ not covered -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered = note: the matched value is of type `Option<Private>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 89b4e06efdacd..f2362c316dfb9 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -37,15 +37,11 @@ LL | match Some(10) { note: `Option<i32>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL | -LL | / pub enum Option<T> { -LL | | /// No value. -LL | | #[lang = "None"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T), - | | ^^^^ not covered -LL | | } - | |_- +LL | pub enum Option<T> { + | ------------------ +... +LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), + | ^^^^ not covered = note: the matched value is of type `Option<i32>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr index 559539178cbe3..98c75953add89 100644 --- a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr +++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr @@ -7,16 +7,11 @@ LL | match UnstableEnum::Stable { note: `UnstableEnum` defined here --> $DIR/auxiliary/unstable.rs:9:5 | -LL | / pub enum UnstableEnum { -LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")] -LL | | Stable, -LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")] -LL | | Stable2, - | | ^^^^^^^ not covered -LL | | #[unstable(feature = "unstable_test_feature", issue = "none")] -LL | | Unstable, -LL | | } - | |_- +LL | pub enum UnstableEnum { + | --------------------- +... +LL | Stable2, + | ^^^^^^^ not covered = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -33,14 +28,8 @@ LL | match UnstableEnum::Stable { note: `UnstableEnum` defined here --> $DIR/auxiliary/unstable.rs:5:1 | -LL | / pub enum UnstableEnum { -LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")] -LL | | Stable, -LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")] -... | -LL | | Unstable, -LL | | } - | |_^ +LL | pub enum UnstableEnum { + | ^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr index b5f1805deef11..f07a25ca89b27 100644 --- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr +++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr @@ -7,15 +7,11 @@ LL | match UnstableEnum::Stable { note: `UnstableEnum` defined here --> $DIR/auxiliary/unstable.rs:11:5 | -LL | / pub enum UnstableEnum { -LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")] -LL | | Stable, -LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")] -... | -LL | | Unstable, - | | ^^^^^^^^ not covered -LL | | } - | |_- +LL | pub enum UnstableEnum { + | --------------------- +... +LL | Unstable, + | ^^^^^^^^ not covered = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr index f174215f257eb..fdf817caea785 100644 --- a/src/test/ui/polymorphization/const_parameters/closures.stderr +++ b/src/test/ui/polymorphization/const_parameters/closures.stderr @@ -14,7 +14,7 @@ LL | pub fn unused<const T: usize>() -> usize { | -------------- generic parameter `T` is unused LL | LL | let add_one = |x: usize| x + 1; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:17:8 @@ -29,7 +29,7 @@ LL | pub fn used_parent<const T: usize>() -> usize { | -------------- generic parameter `T` is unused LL | let x: usize = T; LL | let add_one = |x: usize| x + 1; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:48:13 @@ -38,7 +38,7 @@ LL | pub fn unused_upvar<const T: usize>() -> usize { | -------------- generic parameter `T` is unused LL | let x: usize = T; LL | let y = || x; - | ^^^^ + | ^^ error: aborting due to 4 previous errors; 1 warning emitted diff --git a/src/test/ui/polymorphization/generators.rs b/src/test/ui/polymorphization/generators.rs index 68ea4a026d7bf..779bac0ace29b 100644 --- a/src/test/ui/polymorphization/generators.rs +++ b/src/test/ui/polymorphization/generators.rs @@ -1,5 +1,5 @@ // build-fail -// compile-flags:-Zpolymorphize=on +// compile-flags:-Zpolymorphize=on -Zinline-mir=off #![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)] //~^ WARN the feature `generic_const_exprs` is incomplete diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr index 5edbb119f7869..a24eee5fed1f1 100644 --- a/src/test/ui/polymorphization/generators.stderr +++ b/src/test/ui/polymorphization/generators.stderr @@ -10,16 +10,12 @@ LL | #![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)] error: item has unused generic parameters --> $DIR/generators.rs:35:5 | -LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { - | - generic parameter `T` is unused -LL | / || { -LL | | -LL | | yield 1; -LL | | 2 -LL | | } - | |_____^ +LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + | - generic parameter `T` is unused +LL | || { + | ^^ -note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:35:5: 39:6], u32, u32>` +note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:35:5: 35:7], u32, u32>` --> $DIR/generators.rs:86:5 | LL | finish(unused_type::<u32>()); @@ -28,16 +24,12 @@ LL | finish(unused_type::<u32>()); error: item has unused generic parameters --> $DIR/generators.rs:60:5 | -LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { - | ------------ generic parameter `T` is unused -LL | / || { -LL | | -LL | | yield 1; -LL | | 2 -LL | | } - | |_____^ +LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin { + | ------------ generic parameter `T` is unused +LL | || { + | ^^ -note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:60:5: 64:6], u32, u32>` +note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:60:5: 60:7], u32, u32>` --> $DIR/generators.rs:89:5 | LL | finish(unused_const::<1u32>()); diff --git a/src/test/ui/polymorphization/lifetimes.stderr b/src/test/ui/polymorphization/lifetimes.stderr index 2020256717c4d..4773dd4fa2ef1 100644 --- a/src/test/ui/polymorphization/lifetimes.stderr +++ b/src/test/ui/polymorphization/lifetimes.stderr @@ -11,7 +11,7 @@ LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 { | - generic parameter `T` is unused LL | let _: T = Default::default(); LL | let add_one = |x: u32| x + 1; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs index dea1e21e77fe3..6a5fc2e33de63 100644 --- a/src/test/ui/polymorphization/predicates.rs +++ b/src/test/ui/polymorphization/predicates.rs @@ -1,5 +1,6 @@ // build-fail -// compile-flags:-Zpolymorphize=on +// compile-flags: -Copt-level=0 -Zpolymorphize=on + #![feature(rustc_attrs)] // This test checks that `T` is considered used in `foo`, because it is used in a predicate for diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr index dc6ebceae2197..e5af1d7515f6c 100644 --- a/src/test/ui/polymorphization/predicates.stderr +++ b/src/test/ui/polymorphization/predicates.stderr @@ -1,17 +1,17 @@ error: item has unused generic parameters - --> $DIR/predicates.rs:14:4 + --> $DIR/predicates.rs:15:4 | LL | fn foo<I, T>(_: I) | ^^^ - generic parameter `T` is unused error: item has unused generic parameters - --> $DIR/predicates.rs:23:4 + --> $DIR/predicates.rs:24:4 | LL | fn baz<I, T>(_: I) | ^^^ - generic parameter `T` is unused error: item has unused generic parameters - --> $DIR/predicates.rs:44:19 + --> $DIR/predicates.rs:45:19 | LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E> | - - generic parameter `E` is unused @@ -19,10 +19,10 @@ LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E> | generic parameter `I` is unused ... LL | self.find(|_| true) - | ^^^^^^^^ + | ^^^ error: item has unused generic parameters - --> $DIR/predicates.rs:58:4 + --> $DIR/predicates.rs:59:4 | LL | fn quux<A, B, C: Default>() -> usize | ^^^^ - - generic parameter `B` is unused @@ -30,19 +30,19 @@ LL | fn quux<A, B, C: Default>() -> usize | generic parameter `A` is unused error: item has unused generic parameters - --> $DIR/predicates.rs:75:4 + --> $DIR/predicates.rs:76:4 | LL | fn foobar<F, G>() -> usize | ^^^^^^ - generic parameter `F` is unused error: item has unused generic parameters - --> $DIR/predicates.rs:9:4 + --> $DIR/predicates.rs:10:4 | LL | fn bar<I>() { | ^^^ - generic parameter `I` is unused note: the above error was encountered while instantiating `fn foo::<std::slice::Iter<u32>, T>` - --> $DIR/predicates.rs:85:5 + --> $DIR/predicates.rs:86:5 | LL | foo(x.iter()); | ^^^^^^^^^^^^^ diff --git a/src/test/ui/polymorphization/type_parameters/closures.stderr b/src/test/ui/polymorphization/type_parameters/closures.stderr index 417feebbc5557..94a4a08bd2fc2 100644 --- a/src/test/ui/polymorphization/type_parameters/closures.stderr +++ b/src/test/ui/polymorphization/type_parameters/closures.stderr @@ -5,7 +5,7 @@ LL | pub fn unused<T>() -> u32 { | - generic parameter `T` is unused ... LL | let add_one = |x: u32| x + 1; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:16:8 @@ -20,7 +20,7 @@ LL | pub fn used_parent<T: Default>() -> u32 { | - generic parameter `T` is unused LL | let _: T = Default::default(); LL | let add_one = |x: u32| x + 1; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:94:23 @@ -32,7 +32,7 @@ LL | pub fn unused_all<G: Default>() -> u32 { | - generic parameter `G` is unused LL | LL | let add_one = |x: u32| x + 1; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:92:12 @@ -46,16 +46,11 @@ LL | pub fn unused_all<G: Default>() -> u32 { error: item has unused generic parameters --> $DIR/closures.rs:128:23 | -LL | pub fn used_impl<G: Default>() -> u32 { - | - generic parameter `G` is unused +LL | pub fn used_impl<G: Default>() -> u32 { + | - generic parameter `G` is unused LL | -LL | let add_one = |x: u32| { - | _______________________^ -LL | | -LL | | let _: F = Default::default(); -LL | | x + 1 -LL | | }; - | |_________^ +LL | let add_one = |x: u32| { + | ^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:126:12 @@ -66,16 +61,11 @@ LL | pub fn used_impl<G: Default>() -> u32 { error: item has unused generic parameters --> $DIR/closures.rs:115:23 | -LL | impl<F: Default> Foo<F> { - | - generic parameter `F` is unused +LL | impl<F: Default> Foo<F> { + | - generic parameter `F` is unused ... -LL | let add_one = |x: u32| { - | _______________________^ -LL | | -LL | | let _: G = Default::default(); -LL | | x + 1 -LL | | }; - | |_________^ +LL | let add_one = |x: u32| { + | ^^^^^^^^ error: item has unused generic parameters --> $DIR/closures.rs:113:12 diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr index b51cc5c719f0b..27f88d2817464 100644 --- a/src/test/ui/polymorphization/unsized_cast.stderr +++ b/src/test/ui/polymorphization/unsized_cast.stderr @@ -5,16 +5,16 @@ LL | fn foo<T: Default>() { | - generic parameter `T` is unused LL | let _: T = Default::default(); LL | (|| Box::new(|| {}) as Box<dyn Fn()>)(); - | ^^^^^ + | ^^ error: item has unused generic parameters - --> $DIR/unsized_cast.rs:11:5 + --> $DIR/unsized_cast.rs:11:6 | LL | fn foo<T: Default>() { | - generic parameter `T` is unused LL | let _: T = Default::default(); LL | (|| Box::new(|| {}) as Box<dyn Fn()>)(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ error: item has unused generic parameters --> $DIR/unsized_cast.rs:22:15 @@ -23,21 +23,16 @@ LL | fn foo2<T: Default>() { | - generic parameter `T` is unused ... LL | call(&|| {}, ()); - | ^^^^^ + | ^^ error: item has unused generic parameters - --> $DIR/unsized_cast.rs:19:5 + --> $DIR/unsized_cast.rs:19:6 | -LL | fn foo2<T: Default>() { - | - generic parameter `T` is unused -LL | let _: T = Default::default(); -LL | / (|| { -LL | | -LL | | let call: extern "rust-call" fn(_, _) = Fn::call; -LL | | call(&|| {}, ()); -LL | | -LL | | })(); - | |______^ +LL | fn foo2<T: Default>() { + | - generic parameter `T` is unused +LL | let _: T = Default::default(); +LL | (|| { + | ^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/privacy/issue-30079.stderr b/src/test/ui/privacy/issue-30079.stderr index e40b19420593a..dc98cfe3bb6c4 100644 --- a/src/test/ui/privacy/issue-30079.stderr +++ b/src/test/ui/privacy/issue-30079.stderr @@ -12,19 +12,19 @@ error[E0446]: private type `m2::Priv` in public interface --> $DIR/issue-30079.rs:18:9 | LL | struct Priv; - | ------------ `m2::Priv` declared as private + | ----------- `m2::Priv` declared as private LL | impl ::std::ops::Deref for ::SemiPriv { LL | type Target = Priv; - | ^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^ can't leak private type error[E0446]: private type `m3::Priv` in public interface --> $DIR/issue-30079.rs:35:9 | LL | struct Priv; - | ------------ `m3::Priv` declared as private + | ----------- `m3::Priv` declared as private LL | impl ::SemiPrivTrait for () { LL | type Assoc = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/privacy/privacy5.stderr b/src/test/ui/privacy/privacy5.stderr index d0c0c6b8bb593..680161272cefb 100644 --- a/src/test/ui/privacy/privacy5.stderr +++ b/src/test/ui/privacy/privacy5.stderr @@ -373,7 +373,7 @@ note: the tuple struct constructor `A` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1 | LL | pub struct A(()); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:91:20 @@ -390,7 +390,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:92:20 @@ -407,7 +407,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:95:16 @@ -424,7 +424,7 @@ note: the tuple struct constructor `A` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1 | LL | pub struct A(()); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:96:16 @@ -441,7 +441,7 @@ note: the tuple struct constructor `A` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1 | LL | pub struct A(()); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:97:22 @@ -458,7 +458,7 @@ note: the tuple struct constructor `A` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1 | LL | pub struct A(()); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:98:22 @@ -475,7 +475,7 @@ note: the tuple struct constructor `A` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1 | LL | pub struct A(()); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:100:16 @@ -492,7 +492,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:101:16 @@ -509,7 +509,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:102:22 @@ -526,7 +526,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:103:22 @@ -543,7 +543,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:104:22 @@ -560,7 +560,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:105:16 @@ -577,7 +577,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:107:16 @@ -594,7 +594,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:108:16 @@ -611,7 +611,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:109:16 @@ -628,7 +628,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:110:16 @@ -645,7 +645,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:111:22 @@ -662,7 +662,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:112:22 @@ -679,7 +679,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:113:22 @@ -696,7 +696,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:114:22 @@ -713,7 +713,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:122:21 @@ -730,7 +730,7 @@ note: the tuple struct constructor `A` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:1:1 | LL | pub struct A(()); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `B` is private --> $DIR/privacy5.rs:123:21 @@ -747,7 +747,7 @@ note: the tuple struct constructor `B` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:2:1 | LL | pub struct B(isize); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:124:21 @@ -764,7 +764,7 @@ note: the tuple struct constructor `C` is defined here --> $DIR/auxiliary/privacy_tuple_struct.rs:3:1 | LL | pub struct C(pub isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: aborting due to 48 previous errors diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index ba62a228b09fe..1abeafe398f4d 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -2,16 +2,16 @@ error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:17:9 | LL | struct Priv; - | ------------ `Priv` declared as private + | ----------- `Priv` declared as private ... LL | type A = Priv; - | ^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^ can't leak private type warning: private trait `PrivTr` in public interface (error E0445) --> $DIR/private-in-public-assoc-ty.rs:24:9 | LL | type Alias1: PrivTr; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(private_in_public)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -21,7 +21,7 @@ warning: private type `Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:27:9 | LL | type Alias2: PubTrAux1<Priv> = u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -30,7 +30,7 @@ warning: private type `Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:30:9 | LL | type Alias3: PubTrAux2<A = Priv> = u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -39,19 +39,19 @@ error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:34:9 | LL | struct Priv; - | ------------ `Priv` declared as private + | ----------- `Priv` declared as private ... LL | type Alias4 = Priv; - | ^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^ can't leak private type error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:41:9 | LL | struct Priv; - | ------------ `Priv` declared as private + | ----------- `Priv` declared as private ... LL | type Alias1 = Priv; - | ^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^ can't leak private type error[E0445]: private trait `PrivTr` in public interface --> $DIR/private-in-public-assoc-ty.rs:44:9 @@ -60,7 +60,7 @@ LL | trait PrivTr {} | ------------ `PrivTr` declared as private ... LL | type Exist = impl PrivTr; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^ can't leak private trait error: aborting due to 4 previous errors; 3 warnings emitted diff --git a/src/test/ui/privacy/private-in-public-lint.stderr b/src/test/ui/privacy/private-in-public-lint.stderr index dd5f5b6f8f8f7..1e98e3bed147c 100644 --- a/src/test/ui/privacy/private-in-public-lint.stderr +++ b/src/test/ui/privacy/private-in-public-lint.stderr @@ -2,7 +2,7 @@ error[E0446]: private type `m1::Priv` in public interface --> $DIR/private-in-public-lint.rs:6:9 | LL | struct Priv; - | ------------ `m1::Priv` declared as private + | ----------- `m1::Priv` declared as private ... LL | pub fn f() -> Priv {Priv} | ^^^^^^^^^^^^^^^^^^ can't leak private type @@ -11,7 +11,7 @@ error[E0446]: private type `m2::Priv` in public interface --> $DIR/private-in-public-lint.rs:15:9 | LL | struct Priv; - | ------------ `m2::Priv` declared as private + | ----------- `m2::Priv` declared as private ... LL | pub fn f() -> Priv {Priv} | ^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/private-in-public-warn.stderr b/src/test/ui/privacy/private-in-public-warn.stderr index 5f2c4935bad37..f2ff6cf2fdbc4 100644 --- a/src/test/ui/privacy/private-in-public-warn.stderr +++ b/src/test/ui/privacy/private-in-public-warn.stderr @@ -2,7 +2,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:15:5 | LL | pub type Alias = Priv; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/private-in-public-warn.rs:5:9 @@ -34,7 +34,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:24:9 | LL | const C: Priv = Priv; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -43,10 +43,10 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public-warn.rs:26:9 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | type Alias = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:27:9 @@ -70,7 +70,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:33:9 | LL | pub static ES: Priv; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -79,7 +79,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:35:9 | LL | pub fn ef1(arg: Priv); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -88,7 +88,7 @@ error: private type `types::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:37:9 | LL | pub fn ef2() -> Priv; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -97,16 +97,16 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public-warn.rs:41:9 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | type Alias = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:50:5 | LL | pub type Alias<T: PrivTr> = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -115,7 +115,7 @@ error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:53:5 | LL | pub trait Tr1: PrivTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -124,7 +124,7 @@ error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:55:5 | LL | pub trait Tr2<T: PrivTr> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -133,7 +133,7 @@ error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:58:9 | LL | type Alias: PrivTr; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -151,7 +151,7 @@ error: private trait `traits::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:64:5 | LL | impl<T: PrivTr> Pub<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -160,7 +160,7 @@ error: private trait `traits_where::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:74:5 | LL | pub type Alias<T> where T: PrivTr = T; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -169,7 +169,7 @@ error: private trait `traits_where::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:78:5 | LL | pub trait Tr2<T> where T: PrivTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -187,7 +187,7 @@ error: private trait `traits_where::PrivTr` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:86:5 | LL | impl<T> Pub<T> where T: PrivTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -196,7 +196,7 @@ error: private trait `generics::PrivTr<generics::Pub>` in public interface (erro --> $DIR/private-in-public-warn.rs:98:5 | LL | pub trait Tr1: PrivTr<Pub> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -205,7 +205,7 @@ error: private type `generics::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:101:5 | LL | pub trait Tr2: PubTr<Priv> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -214,7 +214,7 @@ error: private type `generics::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:103:5 | LL | pub trait Tr3: PubTr<[Priv; 1]> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -223,7 +223,7 @@ error: private type `generics::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:105:5 | LL | pub trait Tr4: PubTr<Pub<Priv>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -232,10 +232,10 @@ error[E0446]: private type `impls::Priv` in public interface --> $DIR/private-in-public-warn.rs:132:9 | LL | struct Priv; - | ------------ `impls::Priv` declared as private + | ----------- `impls::Priv` declared as private ... LL | type Alias = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error: private type `aliases_pub::Priv` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:203:9 @@ -250,43 +250,43 @@ error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public-warn.rs:207:9 | LL | struct Priv; - | ------------ `aliases_pub::Priv` declared as private + | ----------- `aliases_pub::Priv` declared as private ... LL | type Check = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public-warn.rs:210:9 | LL | struct Priv; - | ------------ `aliases_pub::Priv` declared as private + | ----------- `aliases_pub::Priv` declared as private ... LL | type Check = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public-warn.rs:213:9 | LL | struct Priv; - | ------------ `aliases_pub::Priv` declared as private + | ----------- `aliases_pub::Priv` declared as private ... LL | type Check = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public-warn.rs:216:9 | LL | struct Priv; - | ------------ `aliases_pub::Priv` declared as private + | ----------- `aliases_pub::Priv` declared as private ... LL | type Check = Priv; - | ^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^ can't leak private type error: private trait `PrivTr1` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:246:5 | LL | pub trait Tr1: PrivUseAliasTr {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -295,7 +295,7 @@ error: private trait `PrivTr1<Priv2>` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:249:5 | LL | pub trait Tr2: PrivUseAliasTr<PrivAlias> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -304,7 +304,7 @@ error: private type `Priv2` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:249:5 | LL | pub trait Tr2: PrivUseAliasTr<PrivAlias> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> diff --git a/src/test/ui/privacy/private-in-public.stderr b/src/test/ui/privacy/private-in-public.stderr index e8bb2cde4be8f..887eebf53efac 100644 --- a/src/test/ui/privacy/private-in-public.stderr +++ b/src/test/ui/privacy/private-in-public.stderr @@ -2,25 +2,25 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:13:5 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub const C: Priv = Priv; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:14:5 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub static S: Priv = Priv; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:15:5 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub fn f1(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -29,7 +29,7 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:16:5 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub fn f2() -> Priv { panic!() } | ^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -38,7 +38,7 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:17:19 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub struct S1(pub Priv); | ^^^^^^^^ can't leak private type @@ -47,7 +47,7 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:18:21 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub struct S2 { pub field: Priv } | ^^^^^^^^^^^^^^^ can't leak private type @@ -56,16 +56,16 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:20:9 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub const C: Priv = Priv; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:21:9 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub fn f1(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -74,7 +74,7 @@ error[E0446]: private type `types::Priv` in public interface --> $DIR/private-in-public.rs:22:9 | LL | struct Priv; - | ------------ `types::Priv` declared as private + | ----------- `types::Priv` declared as private ... LL | pub fn f2() -> Priv { panic!() } | ^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -86,7 +86,7 @@ LL | trait PrivTr {} | ------------ `traits::PrivTr` declared as private ... LL | pub enum E<T: PrivTr> { V(T) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public.rs:32:5 @@ -104,18 +104,16 @@ LL | trait PrivTr {} | ------------ `traits::PrivTr` declared as private ... LL | pub struct S1<T: PrivTr>(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public.rs:34:5 | -LL | trait PrivTr {} - | ------------ `traits::PrivTr` declared as private +LL | trait PrivTr {} + | ------------ `traits::PrivTr` declared as private ... -LL | / impl<T: PrivTr> Pub<T> { -LL | | pub fn f<U: PrivTr>(arg: U) {} -LL | | } - | |_____^ can't leak private trait +LL | impl<T: PrivTr> Pub<T> { + | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits::PrivTr` in public interface --> $DIR/private-in-public.rs:35:9 @@ -133,7 +131,7 @@ LL | trait PrivTr {} | ------------ `traits_where::PrivTr` declared as private ... LL | pub enum E<T> where T: PrivTr { V(T) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits_where::PrivTr` in public interface --> $DIR/private-in-public.rs:46:5 @@ -151,20 +149,16 @@ LL | trait PrivTr {} | ------------ `traits_where::PrivTr` declared as private ... LL | pub struct S1<T>(T) where T: PrivTr; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + | ^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits_where::PrivTr` in public interface --> $DIR/private-in-public.rs:50:5 | -LL | trait PrivTr {} - | ------------ `traits_where::PrivTr` declared as private +LL | trait PrivTr {} + | ------------ `traits_where::PrivTr` declared as private ... -LL | / impl<T> Pub<T> where T: PrivTr { -LL | | -LL | | pub fn f<U>(arg: U) where U: PrivTr {} -LL | | -LL | | } - | |_____^ can't leak private trait +LL | impl<T> Pub<T> where T: PrivTr { + | ^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `traits_where::PrivTr` in public interface --> $DIR/private-in-public.rs:52:9 @@ -179,7 +173,7 @@ error[E0446]: private type `generics::Priv` in public interface --> $DIR/private-in-public.rs:63:5 | LL | struct Priv<T = u8>(T); - | ----------------------- `generics::Priv` declared as private + | ------------------- `generics::Priv` declared as private ... LL | pub fn f1(arg: [Priv; 1]) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -188,7 +182,7 @@ error[E0446]: private type `generics::Priv` in public interface --> $DIR/private-in-public.rs:64:5 | LL | struct Priv<T = u8>(T); - | ----------------------- `generics::Priv` declared as private + | ------------------- `generics::Priv` declared as private ... LL | pub fn f2(arg: Pub<Priv>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -197,7 +191,7 @@ error[E0446]: private type `generics::Priv<generics::Pub>` in public interface --> $DIR/private-in-public.rs:65:5 | LL | struct Priv<T = u8>(T); - | ----------------------- `generics::Priv<generics::Pub>` declared as private + | ------------------- `generics::Priv<generics::Pub>` declared as private ... LL | pub fn f3(arg: Priv<Pub>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -206,7 +200,7 @@ error[E0446]: private type `impls::Priv` in public interface --> $DIR/private-in-public.rs:80:9 | LL | struct Priv; - | ------------ `impls::Priv` declared as private + | ----------- `impls::Priv` declared as private ... LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -224,7 +218,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public.rs:104:5 | LL | struct Priv; - | ------------ `aliases_pub::Priv` declared as private + | ----------- `aliases_pub::Priv` declared as private ... LL | pub fn f3(arg: <Priv as PrivTr>::Assoc) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -233,7 +227,7 @@ error[E0446]: private type `aliases_pub::Priv` in public interface --> $DIR/private-in-public.rs:109:9 | LL | struct Priv; - | ------------ `aliases_pub::Priv` declared as private + | ----------- `aliases_pub::Priv` declared as private ... LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -242,7 +236,7 @@ error[E0446]: private type `Priv1` in public interface --> $DIR/private-in-public.rs:131:5 | LL | struct Priv1; - | ------------- `Priv1` declared as private + | ------------ `Priv1` declared as private ... LL | pub fn f1(arg: PrivUseAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -251,7 +245,7 @@ error[E0446]: private type `Priv2` in public interface --> $DIR/private-in-public.rs:132:5 | LL | struct Priv2; - | ------------- `Priv2` declared as private + | ------------ `Priv2` declared as private ... LL | pub fn f2(arg: PrivAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -269,7 +263,7 @@ error[E0446]: private type `aliases_priv::Priv` in public interface --> $DIR/private-in-public.rs:133:5 | LL | struct Priv; - | ------------ `aliases_priv::Priv` declared as private + | ----------- `aliases_priv::Priv` declared as private ... LL | pub fn f3(arg: <Priv as PrivTr>::Assoc) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -278,7 +272,7 @@ error[E0446]: private type `aliases_params::Priv` in public interface --> $DIR/private-in-public.rs:143:5 | LL | struct Priv; - | ------------ `aliases_params::Priv` declared as private + | ----------- `aliases_params::Priv` declared as private ... LL | pub fn f2(arg: PrivAliasGeneric) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -287,7 +281,7 @@ error[E0446]: private type `aliases_params::Priv` in public interface --> $DIR/private-in-public.rs:145:5 | LL | struct Priv; - | ------------ `aliases_params::Priv` declared as private + | ----------- `aliases_params::Priv` declared as private ... LL | pub fn f3(arg: Result<u8>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr index e7e968839b6fa..aecd8b58c8311 100644 --- a/src/test/ui/privacy/private-inferred-type.stderr +++ b/src/test/ui/privacy/private-inferred-type.stderr @@ -2,19 +2,19 @@ error[E0446]: private type `Priv` in public interface --> $DIR/private-inferred-type.rs:61:36 | LL | struct Priv; - | ------------ `Priv` declared as private + | ----------- `Priv` declared as private ... LL | impl TraitWithAssocTy for u8 { type AssocTy = Priv; } - | ^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^ can't leak private type error[E0446]: private type `S2` in public interface --> $DIR/private-inferred-type.rs:83:9 | LL | struct S2; - | ---------- `S2` declared as private + | --------- `S2` declared as private ... LL | type Target = S2Alias; - | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^ can't leak private type error: type `Priv` is private --> $DIR/private-inferred-type.rs:97:9 diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr index f64b8569015d8..e62a440d8f568 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -20,7 +20,7 @@ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:35:5 | LL | type Foo: OtherTrait; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/privacy/restricted/private-in-public.stderr b/src/test/ui/privacy/restricted/private-in-public.stderr index ee9c031ebff23..65d996f0f0709 100644 --- a/src/test/ui/privacy/restricted/private-in-public.stderr +++ b/src/test/ui/privacy/restricted/private-in-public.stderr @@ -2,7 +2,7 @@ error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public.rs:6:9 | LL | struct Priv; - | ------------ `Priv` declared as private + | ----------- `Priv` declared as private ... LL | pub(crate) fn g(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type @@ -11,7 +11,7 @@ error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public.rs:7:9 | LL | struct Priv; - | ------------ `Priv` declared as private + | ----------- `Priv` declared as private ... LL | pub(crate) fn h(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr index c81520c35cd41..1acd221b42c5f 100644 --- a/src/test/ui/privacy/restricted/test.stderr +++ b/src/test/ui/privacy/restricted/test.stderr @@ -34,7 +34,7 @@ note: the struct `Crate` is defined here --> $DIR/auxiliary/pub_restricted.rs:1:1 | LL | pub(crate) struct Crate; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0603]: function `f` is private --> $DIR/test.rs:30:19 diff --git a/src/test/ui/privacy/where-priv-type.stderr b/src/test/ui/privacy/where-priv-type.stderr index 378c14810d92d..7eb71346ae9c8 100644 --- a/src/test/ui/privacy/where-priv-type.stderr +++ b/src/test/ui/privacy/where-priv-type.stderr @@ -1,13 +1,8 @@ warning: private type `PrivTy` in public interface (error E0446) --> $DIR/where-priv-type.rs:19:1 | -LL | / pub struct S -LL | | -LL | | -LL | | where -LL | | PrivTy: -LL | | {} - | |__^ +LL | pub struct S + | ^^^^^^^^^^^^ | = note: `#[warn(private_in_public)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -16,13 +11,8 @@ LL | | {} warning: private type `PrivTy` in public interface (error E0446) --> $DIR/where-priv-type.rs:27:1 | -LL | / pub enum E -LL | | -LL | | -LL | | where -LL | | PrivTy: -LL | | {} - | |__^ +LL | pub enum E + | ^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> @@ -43,17 +33,11 @@ LL | | PrivTy: error[E0446]: private type `PrivTy` in public interface --> $DIR/where-priv-type.rs:43:1 | -LL | struct PrivTy; - | -------------- `PrivTy` declared as private +LL | struct PrivTy; + | ------------- `PrivTy` declared as private ... -LL | / impl S -LL | | -LL | | where -LL | | PrivTy: -... | -LL | | {} -LL | | } - | |_^ can't leak private type +LL | impl S + | ^^^^^^ can't leak private type warning: private type `PrivTy` in public interface (error E0446) --> $DIR/where-priv-type.rs:48:5 @@ -72,7 +56,7 @@ error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface --> $DIR/where-priv-type.rs:80:5 | LL | type AssocTy = Const<{ my_const_fn(U) }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^ can't leak private type ... LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private diff --git a/src/test/ui/privacy/where-pub-type-impls-priv-trait.stderr b/src/test/ui/privacy/where-pub-type-impls-priv-trait.stderr index 9ce7b9a139f5e..a433cebbbc090 100644 --- a/src/test/ui/privacy/where-pub-type-impls-priv-trait.stderr +++ b/src/test/ui/privacy/where-pub-type-impls-priv-trait.stderr @@ -1,28 +1,20 @@ error[E0445]: private trait `PrivTr` in public interface --> $DIR/where-pub-type-impls-priv-trait.rs:19:1 | -LL | trait PrivTr {} - | ------------ `PrivTr` declared as private +LL | trait PrivTr {} + | ------------ `PrivTr` declared as private ... -LL | / pub struct S -LL | | -LL | | where -LL | | PubTy: PrivTr -LL | | {} - | |__^ can't leak private trait +LL | pub struct S + | ^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `PrivTr` in public interface --> $DIR/where-pub-type-impls-priv-trait.rs:26:1 | -LL | trait PrivTr {} - | ------------ `PrivTr` declared as private +LL | trait PrivTr {} + | ------------ `PrivTr` declared as private ... -LL | / pub enum E -LL | | -LL | | where -LL | | PubTy: PrivTr -LL | | {} - | |__^ can't leak private trait +LL | pub enum E + | ^^^^^^^^^^ can't leak private trait error[E0445]: private trait `PrivTr` in public interface --> $DIR/where-pub-type-impls-priv-trait.rs:33:1 @@ -39,17 +31,11 @@ LL | | PubTy: PrivTr error[E0445]: private trait `PrivTr` in public interface --> $DIR/where-pub-type-impls-priv-trait.rs:40:1 | -LL | trait PrivTr {} - | ------------ `PrivTr` declared as private +LL | trait PrivTr {} + | ------------ `PrivTr` declared as private ... -LL | / impl S -LL | | -LL | | where -LL | | PubTy: PrivTr -... | -LL | | {} -LL | | } - | |_^ can't leak private trait +LL | impl S + | ^^^^^^ can't leak private trait error[E0445]: private trait `PrivTr` in public interface --> $DIR/where-pub-type-impls-priv-trait.rs:45:5 diff --git a/src/test/ui/proc-macro/attribute-with-error.stderr b/src/test/ui/proc-macro/attribute-with-error.stderr index 127c49957c1e5..7f3a7e670b9b7 100644 --- a/src/test/ui/proc-macro/attribute-with-error.stderr +++ b/src/test/ui/proc-macro/attribute-with-error.stderr @@ -1,11 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/attribute-with-error.rs:25:22 - | -LL | let a: i32 = "foo"; - | --- ^^^^^ expected `i32`, found `&str` - | | - | expected due to this - error[E0308]: mismatched types --> $DIR/attribute-with-error.rs:10:18 | @@ -22,6 +14,14 @@ LL | let b: i32 = "f'oo"; | | | expected due to this +error[E0308]: mismatched types + --> $DIR/attribute-with-error.rs:25:22 + | +LL | let a: i32 = "foo"; + | --- ^^^^^ expected `i32`, found `&str` + | | + | expected due to this + error[E0308]: mismatched types --> $DIR/attribute-with-error.rs:35:22 | diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs index 2bc34f3c6bfc0..5463e79d74e0a 100644 --- a/src/test/ui/proc-macro/auxiliary/expand-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs @@ -10,6 +10,72 @@ extern crate proc_macro; use proc_macro::*; use std::str::FromStr; +// Flatten the TokenStream, removing any toplevel `Delimiter::None`s for +// comparison. +fn flatten(ts: TokenStream) -> Vec<TokenTree> { + ts.into_iter() + .flat_map(|tt| match &tt { + TokenTree::Group(group) if group.delimiter() == Delimiter::None => { + flatten(group.stream()) + } + _ => vec![tt], + }) + .collect() +} + +// Assert that two TokenStream values are roughly equal to one-another. +fn assert_ts_eq(lhs: &TokenStream, rhs: &TokenStream) { + let ltts = flatten(lhs.clone()); + let rtts = flatten(rhs.clone()); + + if ltts.len() != rtts.len() { + panic!( + "expected the same number of tts ({} == {})\nlhs:\n{:#?}\nrhs:\n{:#?}", + ltts.len(), + rtts.len(), + lhs, + rhs + ) + } + + for (ltt, rtt) in ltts.iter().zip(&rtts) { + match (ltt, rtt) { + (TokenTree::Group(l), TokenTree::Group(r)) => { + assert_eq!( + l.delimiter(), + r.delimiter(), + "expected delimiters to match for {:?} and {:?}", + l, + r + ); + assert_ts_eq(&l.stream(), &r.stream()); + } + (TokenTree::Punct(l), TokenTree::Punct(r)) => assert_eq!( + (l.as_char(), l.spacing()), + (r.as_char(), r.spacing()), + "expected punct to match for {:?} and {:?}", + l, + r + ), + (TokenTree::Ident(l), TokenTree::Ident(r)) => assert_eq!( + l.to_string(), + r.to_string(), + "expected ident to match for {:?} and {:?}", + l, + r + ), + (TokenTree::Literal(l), TokenTree::Literal(r)) => assert_eq!( + l.to_string(), + r.to_string(), + "expected literal to match for {:?} and {:?}", + l, + r + ), + (l, r) => panic!("expected type to match for {:?} and {:?}", l, r), + } + } +} + #[proc_macro] pub fn expand_expr_is(input: TokenStream) -> TokenStream { let mut iter = input.into_iter(); @@ -31,6 +97,9 @@ pub fn expand_expr_is(input: TokenStream) -> TokenStream { expanded.to_string() ); + // Also compare the raw tts to make sure they line up. + assert_ts_eq(&expected, &expanded); + TokenStream::new() } @@ -48,7 +117,7 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream { // invocation expand to the same literal. let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string(); let parse_t = TokenStream::from_str("file!{}") - .unwrap() + .unwrap() .expand_expr() .expect("expand_expr failed on internal macro") .to_string(); diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs index a3133a1a79070..fdf3ca2e261b6 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs @@ -1,17 +1,9 @@ // aux-build:invalid-punct-ident.rs -// rustc-env:RUST_BACKTRACE=0 - -// FIXME https://github.com/rust-lang/rust/issues/59998 -// normalize-stderr-test "thread.*panicked.*proc_macro_server.rs.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" -// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" -// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" -// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" -// normalize-stderr-test "note: compiler flags.*\n\n" -> "" -// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" -// normalize-stderr-test "query stack during panic:\n" -> "" -// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" -// normalize-stderr-test "end of query stack\n" -> "" +// ignore-stage1 +// only-linux +// +// FIXME: This should be a normal (stage1, all platforms) test in +// src/test/ui/proc-macro once issue #59998 is fixed. #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index eaf41c080faf4..bb0a48cb16b8d 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-1.rs:19:1 + --> $DIR/invalid-punct-ident-1.rs:11:1 | LL | invalid_punct!(); | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/parent-source-spans.stderr b/src/test/ui/proc-macro/parent-source-spans.stderr index 4548269b50793..3c46b95cbc685 100644 --- a/src/test/ui/proc-macro/parent-source-spans.stderr +++ b/src/test/ui/proc-macro/parent-source-spans.stderr @@ -148,7 +148,7 @@ LL | one!("hello", "world"); ::: $SRC_DIR/core/src/result.rs:LL:COL | LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), - | --------------------------------------------------- similarly named tuple variant `Ok` defined here + | -- similarly named tuple variant `Ok` defined here | = note: this error originates in the macro `parent_source_spans` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -164,7 +164,7 @@ LL | two!("yay", "rust"); ::: $SRC_DIR/core/src/result.rs:LL:COL | LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), - | --------------------------------------------------- similarly named tuple variant `Ok` defined here + | -- similarly named tuple variant `Ok` defined here | = note: this error originates in the macro `parent_source_spans` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -180,7 +180,7 @@ LL | three!("hip", "hop"); ::: $SRC_DIR/core/src/result.rs:LL:COL | LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), - | --------------------------------------------------- similarly named tuple variant `Ok` defined here + | -- similarly named tuple variant `Ok` defined here | = note: this error originates in the macro `parent_source_spans` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr index e518c6ab80032..a534b9d5377ad 100644 --- a/src/test/ui/proc-macro/resolve-error.stderr +++ b/src/test/ui/proc-macro/resolve-error.stderr @@ -76,7 +76,7 @@ LL | #[derive(Dlone)] ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | pub macro Clone($item:item) { - | --------------------------- similarly named derive macro `Clone` defined here + | --------------- similarly named derive macro `Clone` defined here error: cannot find derive macro `Dlone` in this scope --> $DIR/resolve-error.rs:35:10 @@ -87,7 +87,7 @@ LL | #[derive(Dlone)] ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | pub macro Clone($item:item) { - | --------------------------- similarly named derive macro `Clone` defined here + | --------------- similarly named derive macro `Clone` defined here error: cannot find attribute `FooWithLongNan` in this scope --> $DIR/resolve-error.rs:32:3 diff --git a/src/test/ui/proc-macro/signature.stderr b/src/test/ui/proc-macro/signature.stderr index 78b0beff0da39..a6bd98ddb1977 100644 --- a/src/test/ui/proc-macro/signature.stderr +++ b/src/test/ui/proc-macro/signature.stderr @@ -5,10 +5,7 @@ LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { LL | | LL | | loop {} LL | | } - | | ^ - | | | - | |_call the function in a closure: `|| unsafe { /* code */ }` - | required by a bound introduced by this call + | |_^ call the function in a closure: `|| unsafe { /* code */ }` | = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}` = note: unsafe function cannot be called generically without an unsafe block diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr index 29d45858ff15c..39d4f5ac8d3cf 100644 --- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr +++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr @@ -2,28 +2,28 @@ error[E0446]: private type `Snail` in public interface --> $DIR/issue-33174-restricted-type-in-public-interface.rs:18:1 | LL | pub(crate) struct Snail; - | ------------------------ `Snail` declared as private + | ----------------------- `Snail` declared as private ... LL | pub type Helix_pomatia = Shell<Snail>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: crate-private type `Turtle` in public interface --> $DIR/issue-33174-restricted-type-in-public-interface.rs:21:1 | LL | pub(super) struct Turtle; - | ------------------------- `Turtle` declared as crate-private + | ------------------------ `Turtle` declared as crate-private ... LL | pub type Dermochelys_coriacea = Shell<sea::Turtle>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-private type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-private type error[E0446]: private type `Tortoise` in public interface --> $DIR/issue-33174-restricted-type-in-public-interface.rs:24:1 | LL | struct Tortoise; - | ---------------- `Tortoise` declared as private + | --------------- `Tortoise` declared as private ... LL | pub type Testudo_graeca = Shell<Tortoise>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type error: aborting due to 3 previous errors diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs index c857eb459b8de..c9e93174e20fe 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs @@ -1,18 +1,14 @@ -// Dropck shouldn't hit a recursion limit from checking `S<u32>` since it has -// no free regions or type parameters. -// Codegen however, has to error for the infinitely many `drop_in_place` -// functions it has been asked to create. - -// build-fail -// normalize-stderr-test: ".nll/" -> "/" -// compile-flags: -Zmir-opt-level=0 +// `S` is infinitely recursing so it's not possible to generate a finite +// drop impl (ignoring polymorphization). +// +// Dropck should therefore detect that this is the case and eagerly error. struct S<T> { t: T, s: Box<S<fn(u: T)>>, } -fn f(x: S<u32>) {} +fn f(x: S<u32>) {} //~ ERROR overflow while adding drop-check rules for S<u32> fn main() { // Force instantiation. diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index d749ee00c22bf..1da29be43db86 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,15 +1,10 @@ -error: reached the recursion limit while instantiating `std::ptr::drop_in_place::<S<fn(f...)))))))))))))))))))))))))))))>))` - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +error[E0320]: overflow while adding drop-check rules for S<u32> + --> $DIR/issue-38591-non-regular-dropck-recursion.rs:11:6 | -LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn f(x: S<u32>) {} + | ^ | -note: `std::ptr::drop_in_place` defined here - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | -LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt' + = note: overflowed on S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))> error: aborting due to previous error diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs index aa3f66b2e28e1..e647f0ff4fb8b 100644 --- a/src/test/ui/recursion/issue-83150.rs +++ b/src/test/ui/recursion/issue-83150.rs @@ -1,5 +1,6 @@ // build-fail -//~^ ERROR overflow evaluating the requirement +// compile-flags: -Copt-level=0 +//~^^ ERROR overflow evaluating the requirement fn main() { let mut iter = 0u8..1; diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr index 4c8469be62616..89a832984712a 100644 --- a/src/test/ui/recursion/issue-83150.stderr +++ b/src/test/ui/recursion/issue-83150.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-83150.rs:9:1 + --> $DIR/issue-83150.rs:10:1 | LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -9,10 +9,10 @@ LL | func(&mut iter.map(|x| x + 1)) = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>: Iterator` +error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>: Iterator` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) - = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>` + = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/recursion/issue-86784.rs b/src/test/ui/recursion/issue-86784.rs new file mode 100644 index 0000000000000..34f4aaedb326f --- /dev/null +++ b/src/test/ui/recursion/issue-86784.rs @@ -0,0 +1,2597 @@ +// build-pass + +fn main() { + let _temp_1 = 0; + let _temp_2 = 0; + let _temp_3 = 0; + let _temp_4 = 0; + let _temp_5 = 0; + let _temp_6 = 0; + let _temp_7 = 0; + let _temp_8 = 0; + let _temp_9 = 0; + let _temp_10 = 0; + let _temp_11 = 0; + let _temp_12 = 0; + let _temp_13 = 0; + let _temp_14 = 0; + let _temp_15 = 0; + let _temp_16 = 0; + let _temp_17 = 0; + let _temp_18 = 0; + let _temp_19 = 0; + let _temp_20 = 0; + let _temp_21 = 0; + let _temp_22 = 0; + let _temp_23 = 0; + let _temp_24 = 0; + let _temp_25 = 0; + let _temp_26 = 0; + let _temp_27 = 0; + let _temp_28 = 0; + let _temp_29 = 0; + let _temp_30 = 0; + let _temp_31 = 0; + let _temp_32 = 0; + let _temp_33 = 0; + let _temp_34 = 0; + let _temp_35 = 0; + let _temp_36 = 0; + let _temp_37 = 0; + let _temp_38 = 0; + let _temp_39 = 0; + let _temp_40 = 0; + let _temp_41 = 0; + let _temp_42 = 0; + let _temp_43 = 0; + let _temp_44 = 0; + let _temp_45 = 0; + let _temp_46 = 0; + let _temp_47 = 0; + let _temp_48 = 0; + let _temp_49 = 0; + let _temp_50 = 0; + let _temp_51 = 0; + let _temp_52 = 0; + let _temp_53 = 0; + let _temp_54 = 0; + let _temp_55 = 0; + let _temp_56 = 0; + let _temp_57 = 0; + let _temp_58 = 0; + let _temp_59 = 0; + let _temp_60 = 0; + let _temp_61 = 0; + let _temp_62 = 0; + let _temp_63 = 0; + let _temp_64 = 0; + let _temp_65 = 0; + let _temp_66 = 0; + let _temp_67 = 0; + let _temp_68 = 0; + let _temp_69 = 0; + let _temp_70 = 0; + let _temp_71 = 0; + let _temp_72 = 0; + let _temp_73 = 0; + let _temp_74 = 0; + let _temp_75 = 0; + let _temp_76 = 0; + let _temp_77 = 0; + let _temp_78 = 0; + let _temp_79 = 0; + let _temp_80 = 0; + let _temp_81 = 0; + let _temp_82 = 0; + let _temp_83 = 0; + let _temp_84 = 0; + let _temp_85 = 0; + let _temp_86 = 0; + let _temp_87 = 0; + let _temp_88 = 0; + let _temp_89 = 0; + let _temp_90 = 0; + let _temp_91 = 0; + let _temp_92 = 0; + let _temp_93 = 0; + let _temp_94 = 0; + let _temp_95 = 0; + let _temp_96 = 0; + let _temp_97 = 0; + let _temp_98 = 0; + let _temp_99 = 0; + let _temp_100 = 0; + let _temp_101 = 0; + let _temp_102 = 0; + let _temp_103 = 0; + let _temp_104 = 0; + let _temp_105 = 0; + let _temp_106 = 0; + let _temp_107 = 0; + let _temp_108 = 0; + let _temp_109 = 0; + let _temp_110 = 0; + let _temp_111 = 0; + let _temp_112 = 0; + let _temp_113 = 0; + let _temp_114 = 0; + let _temp_115 = 0; + let _temp_116 = 0; + let _temp_117 = 0; + let _temp_118 = 0; + let _temp_119 = 0; + let _temp_120 = 0; + let _temp_121 = 0; + let _temp_122 = 0; + let _temp_123 = 0; + let _temp_124 = 0; + let _temp_125 = 0; + let _temp_126 = 0; + let _temp_127 = 0; + let _temp_128 = 0; + let _temp_129 = 0; + let _temp_130 = 0; + let _temp_131 = 0; + let _temp_132 = 0; + let _temp_133 = 0; + let _temp_134 = 0; + let _temp_135 = 0; + let _temp_136 = 0; + let _temp_137 = 0; + let _temp_138 = 0; + let _temp_139 = 0; + let _temp_140 = 0; + let _temp_141 = 0; + let _temp_142 = 0; + let _temp_143 = 0; + let _temp_144 = 0; + let _temp_145 = 0; + let _temp_146 = 0; + let _temp_147 = 0; + let _temp_148 = 0; + let _temp_149 = 0; + let _temp_150 = 0; + let _temp_151 = 0; + let _temp_152 = 0; + let _temp_153 = 0; + let _temp_154 = 0; + let _temp_155 = 0; + let _temp_156 = 0; + let _temp_157 = 0; + let _temp_158 = 0; + let _temp_159 = 0; + let _temp_160 = 0; + let _temp_161 = 0; + let _temp_162 = 0; + let _temp_163 = 0; + let _temp_164 = 0; + let _temp_165 = 0; + let _temp_166 = 0; + let _temp_167 = 0; + let _temp_168 = 0; + let _temp_169 = 0; + let _temp_170 = 0; + let _temp_171 = 0; + let _temp_172 = 0; + let _temp_173 = 0; + let _temp_174 = 0; + let _temp_175 = 0; + let _temp_176 = 0; + let _temp_177 = 0; + let _temp_178 = 0; + let _temp_179 = 0; + let _temp_180 = 0; + let _temp_181 = 0; + let _temp_182 = 0; + let _temp_183 = 0; + let _temp_184 = 0; + let _temp_185 = 0; + let _temp_186 = 0; + let _temp_187 = 0; + let _temp_188 = 0; + let _temp_189 = 0; + let _temp_190 = 0; + let _temp_191 = 0; + let _temp_192 = 0; + let _temp_193 = 0; + let _temp_194 = 0; + let _temp_195 = 0; + let _temp_196 = 0; + let _temp_197 = 0; + let _temp_198 = 0; + let _temp_199 = 0; + let _temp_200 = 0; + let _temp_201 = 0; + let _temp_202 = 0; + let _temp_203 = 0; + let _temp_204 = 0; + let _temp_205 = 0; + let _temp_206 = 0; + let _temp_207 = 0; + let _temp_208 = 0; + let _temp_209 = 0; + let _temp_210 = 0; + let _temp_211 = 0; + let _temp_212 = 0; + let _temp_213 = 0; + let _temp_214 = 0; + let _temp_215 = 0; + let _temp_216 = 0; + let _temp_217 = 0; + let _temp_218 = 0; + let _temp_219 = 0; + let _temp_220 = 0; + let _temp_221 = 0; + let _temp_222 = 0; + let _temp_223 = 0; + let _temp_224 = 0; + let _temp_225 = 0; + let _temp_226 = 0; + let _temp_227 = 0; + let _temp_228 = 0; + let _temp_229 = 0; + let _temp_230 = 0; + let _temp_231 = 0; + let _temp_232 = 0; + let _temp_233 = 0; + let _temp_234 = 0; + let _temp_235 = 0; + let _temp_236 = 0; + let _temp_237 = 0; + let _temp_238 = 0; + let _temp_239 = 0; + let _temp_240 = 0; + let _temp_241 = 0; + let _temp_242 = 0; + let _temp_243 = 0; + let _temp_244 = 0; + let _temp_245 = 0; + let _temp_246 = 0; + let _temp_247 = 0; + let _temp_248 = 0; + let _temp_249 = 0; + let _temp_250 = 0; + let _temp_251 = 0; + let _temp_252 = 0; + let _temp_253 = 0; + let _temp_254 = 0; + let _temp_255 = 0; + let _temp_256 = 0; + let _temp_257 = 0; + let _temp_258 = 0; + let _temp_259 = 0; + let _temp_260 = 0; + let _temp_261 = 0; + let _temp_262 = 0; + let _temp_263 = 0; + let _temp_264 = 0; + let _temp_265 = 0; + let _temp_266 = 0; + let _temp_267 = 0; + let _temp_268 = 0; + let _temp_269 = 0; + let _temp_270 = 0; + let _temp_271 = 0; + let _temp_272 = 0; + let _temp_273 = 0; + let _temp_274 = 0; + let _temp_275 = 0; + let _temp_276 = 0; + let _temp_277 = 0; + let _temp_278 = 0; + let _temp_279 = 0; + let _temp_280 = 0; + let _temp_281 = 0; + let _temp_282 = 0; + let _temp_283 = 0; + let _temp_284 = 0; + let _temp_285 = 0; + let _temp_286 = 0; + let _temp_287 = 0; + let _temp_288 = 0; + let _temp_289 = 0; + let _temp_290 = 0; + let _temp_291 = 0; + let _temp_292 = 0; + let _temp_293 = 0; + let _temp_294 = 0; + let _temp_295 = 0; + let _temp_296 = 0; + let _temp_297 = 0; + let _temp_298 = 0; + let _temp_299 = 0; + let _temp_300 = 0; + let _temp_301 = 0; + let _temp_302 = 0; + let _temp_303 = 0; + let _temp_304 = 0; + let _temp_305 = 0; + let _temp_306 = 0; + let _temp_307 = 0; + let _temp_308 = 0; + let _temp_309 = 0; + let _temp_310 = 0; + let _temp_311 = 0; + let _temp_312 = 0; + let _temp_313 = 0; + let _temp_314 = 0; + let _temp_315 = 0; + let _temp_316 = 0; + let _temp_317 = 0; + let _temp_318 = 0; + let _temp_319 = 0; + let _temp_320 = 0; + let _temp_321 = 0; + let _temp_322 = 0; + let _temp_323 = 0; + let _temp_324 = 0; + let _temp_325 = 0; + let _temp_326 = 0; + let _temp_327 = 0; + let _temp_328 = 0; + let _temp_329 = 0; + let _temp_330 = 0; + let _temp_331 = 0; + let _temp_332 = 0; + let _temp_333 = 0; + let _temp_334 = 0; + let _temp_335 = 0; + let _temp_336 = 0; + let _temp_337 = 0; + let _temp_338 = 0; + let _temp_339 = 0; + let _temp_340 = 0; + let _temp_341 = 0; + let _temp_342 = 0; + let _temp_343 = 0; + let _temp_344 = 0; + let _temp_345 = 0; + let _temp_346 = 0; + let _temp_347 = 0; + let _temp_348 = 0; + let _temp_349 = 0; + let _temp_350 = 0; + let _temp_351 = 0; + let _temp_352 = 0; + let _temp_353 = 0; + let _temp_354 = 0; + let _temp_355 = 0; + let _temp_356 = 0; + let _temp_357 = 0; + let _temp_358 = 0; + let _temp_359 = 0; + let _temp_360 = 0; + let _temp_361 = 0; + let _temp_362 = 0; + let _temp_363 = 0; + let _temp_364 = 0; + let _temp_365 = 0; + let _temp_366 = 0; + let _temp_367 = 0; + let _temp_368 = 0; + let _temp_369 = 0; + let _temp_370 = 0; + let _temp_371 = 0; + let _temp_372 = 0; + let _temp_373 = 0; + let _temp_374 = 0; + let _temp_375 = 0; + let _temp_376 = 0; + let _temp_377 = 0; + let _temp_378 = 0; + let _temp_379 = 0; + let _temp_380 = 0; + let _temp_381 = 0; + let _temp_382 = 0; + let _temp_383 = 0; + let _temp_384 = 0; + let _temp_385 = 0; + let _temp_386 = 0; + let _temp_387 = 0; + let _temp_388 = 0; + let _temp_389 = 0; + let _temp_390 = 0; + let _temp_391 = 0; + let _temp_392 = 0; + let _temp_393 = 0; + let _temp_394 = 0; + let _temp_395 = 0; + let _temp_396 = 0; + let _temp_397 = 0; + let _temp_398 = 0; + let _temp_399 = 0; + let _temp_400 = 0; + let _temp_401 = 0; + let _temp_402 = 0; + let _temp_403 = 0; + let _temp_404 = 0; + let _temp_405 = 0; + let _temp_406 = 0; + let _temp_407 = 0; + let _temp_408 = 0; + let _temp_409 = 0; + let _temp_410 = 0; + let _temp_411 = 0; + let _temp_412 = 0; + let _temp_413 = 0; + let _temp_414 = 0; + let _temp_415 = 0; + let _temp_416 = 0; + let _temp_417 = 0; + let _temp_418 = 0; + let _temp_419 = 0; + let _temp_420 = 0; + let _temp_421 = 0; + let _temp_422 = 0; + let _temp_423 = 0; + let _temp_424 = 0; + let _temp_425 = 0; + let _temp_426 = 0; + let _temp_427 = 0; + let _temp_428 = 0; + let _temp_429 = 0; + let _temp_430 = 0; + let _temp_431 = 0; + let _temp_432 = 0; + let _temp_433 = 0; + let _temp_434 = 0; + let _temp_435 = 0; + let _temp_436 = 0; + let _temp_437 = 0; + let _temp_438 = 0; + let _temp_439 = 0; + let _temp_440 = 0; + let _temp_441 = 0; + let _temp_442 = 0; + let _temp_443 = 0; + let _temp_444 = 0; + let _temp_445 = 0; + let _temp_446 = 0; + let _temp_447 = 0; + let _temp_448 = 0; + let _temp_449 = 0; + let _temp_450 = 0; + let _temp_451 = 0; + let _temp_452 = 0; + let _temp_453 = 0; + let _temp_454 = 0; + let _temp_455 = 0; + let _temp_456 = 0; + let _temp_457 = 0; + let _temp_458 = 0; + let _temp_459 = 0; + let _temp_460 = 0; + let _temp_461 = 0; + let _temp_462 = 0; + let _temp_463 = 0; + let _temp_464 = 0; + let _temp_465 = 0; + let _temp_466 = 0; + let _temp_467 = 0; + let _temp_468 = 0; + let _temp_469 = 0; + let _temp_470 = 0; + let _temp_471 = 0; + let _temp_472 = 0; + let _temp_473 = 0; + let _temp_474 = 0; + let _temp_475 = 0; + let _temp_476 = 0; + let _temp_477 = 0; + let _temp_478 = 0; + let _temp_479 = 0; + let _temp_480 = 0; + let _temp_481 = 0; + let _temp_482 = 0; + let _temp_483 = 0; + let _temp_484 = 0; + let _temp_485 = 0; + let _temp_486 = 0; + let _temp_487 = 0; + let _temp_488 = 0; + let _temp_489 = 0; + let _temp_490 = 0; + let _temp_491 = 0; + let _temp_492 = 0; + let _temp_493 = 0; + let _temp_494 = 0; + let _temp_495 = 0; + let _temp_496 = 0; + let _temp_497 = 0; + let _temp_498 = 0; + let _temp_499 = 0; + let _temp_500 = 0; + let _temp_501 = 0; + let _temp_502 = 0; + let _temp_503 = 0; + let _temp_504 = 0; + let _temp_505 = 0; + let _temp_506 = 0; + let _temp_507 = 0; + let _temp_508 = 0; + let _temp_509 = 0; + let _temp_510 = 0; + let _temp_511 = 0; + let _temp_512 = 0; + let _temp_513 = 0; + let _temp_514 = 0; + let _temp_515 = 0; + let _temp_516 = 0; + let _temp_517 = 0; + let _temp_518 = 0; + let _temp_519 = 0; + let _temp_520 = 0; + let _temp_521 = 0; + let _temp_522 = 0; + let _temp_523 = 0; + let _temp_524 = 0; + let _temp_525 = 0; + let _temp_526 = 0; + let _temp_527 = 0; + let _temp_528 = 0; + let _temp_529 = 0; + let _temp_530 = 0; + let _temp_531 = 0; + let _temp_532 = 0; + let _temp_533 = 0; + let _temp_534 = 0; + let _temp_535 = 0; + let _temp_536 = 0; + let _temp_537 = 0; + let _temp_538 = 0; + let _temp_539 = 0; + let _temp_540 = 0; + let _temp_541 = 0; + let _temp_542 = 0; + let _temp_543 = 0; + let _temp_544 = 0; + let _temp_545 = 0; + let _temp_546 = 0; + let _temp_547 = 0; + let _temp_548 = 0; + let _temp_549 = 0; + let _temp_550 = 0; + let _temp_551 = 0; + let _temp_552 = 0; + let _temp_553 = 0; + let _temp_554 = 0; + let _temp_555 = 0; + let _temp_556 = 0; + let _temp_557 = 0; + let _temp_558 = 0; + let _temp_559 = 0; + let _temp_560 = 0; + let _temp_561 = 0; + let _temp_562 = 0; + let _temp_563 = 0; + let _temp_564 = 0; + let _temp_565 = 0; + let _temp_566 = 0; + let _temp_567 = 0; + let _temp_568 = 0; + let _temp_569 = 0; + let _temp_570 = 0; + let _temp_571 = 0; + let _temp_572 = 0; + let _temp_573 = 0; + let _temp_574 = 0; + let _temp_575 = 0; + let _temp_576 = 0; + let _temp_577 = 0; + let _temp_578 = 0; + let _temp_579 = 0; + let _temp_580 = 0; + let _temp_581 = 0; + let _temp_582 = 0; + let _temp_583 = 0; + let _temp_584 = 0; + let _temp_585 = 0; + let _temp_586 = 0; + let _temp_587 = 0; + let _temp_588 = 0; + let _temp_589 = 0; + let _temp_590 = 0; + let _temp_591 = 0; + let _temp_592 = 0; + let _temp_593 = 0; + let _temp_594 = 0; + let _temp_595 = 0; + let _temp_596 = 0; + let _temp_597 = 0; + let _temp_598 = 0; + let _temp_599 = 0; + let _temp_600 = 0; + let _temp_601 = 0; + let _temp_602 = 0; + let _temp_603 = 0; + let _temp_604 = 0; + let _temp_605 = 0; + let _temp_606 = 0; + let _temp_607 = 0; + let _temp_608 = 0; + let _temp_609 = 0; + let _temp_610 = 0; + let _temp_611 = 0; + let _temp_612 = 0; + let _temp_613 = 0; + let _temp_614 = 0; + let _temp_615 = 0; + let _temp_616 = 0; + let _temp_617 = 0; + let _temp_618 = 0; + let _temp_619 = 0; + let _temp_620 = 0; + let _temp_621 = 0; + let _temp_622 = 0; + let _temp_623 = 0; + let _temp_624 = 0; + let _temp_625 = 0; + let _temp_626 = 0; + let _temp_627 = 0; + let _temp_628 = 0; + let _temp_629 = 0; + let _temp_630 = 0; + let _temp_631 = 0; + let _temp_632 = 0; + let _temp_633 = 0; + let _temp_634 = 0; + let _temp_635 = 0; + let _temp_636 = 0; + let _temp_637 = 0; + let _temp_638 = 0; + let _temp_639 = 0; + let _temp_640 = 0; + let _temp_641 = 0; + let _temp_642 = 0; + let _temp_643 = 0; + let _temp_644 = 0; + let _temp_645 = 0; + let _temp_646 = 0; + let _temp_647 = 0; + let _temp_648 = 0; + let _temp_649 = 0; + let _temp_650 = 0; + let _temp_651 = 0; + let _temp_652 = 0; + let _temp_653 = 0; + let _temp_654 = 0; + let _temp_655 = 0; + let _temp_656 = 0; + let _temp_657 = 0; + let _temp_658 = 0; + let _temp_659 = 0; + let _temp_660 = 0; + let _temp_661 = 0; + let _temp_662 = 0; + let _temp_663 = 0; + let _temp_664 = 0; + let _temp_665 = 0; + let _temp_666 = 0; + let _temp_667 = 0; + let _temp_668 = 0; + let _temp_669 = 0; + let _temp_670 = 0; + let _temp_671 = 0; + let _temp_672 = 0; + let _temp_673 = 0; + let _temp_674 = 0; + let _temp_675 = 0; + let _temp_676 = 0; + let _temp_677 = 0; + let _temp_678 = 0; + let _temp_679 = 0; + let _temp_680 = 0; + let _temp_681 = 0; + let _temp_682 = 0; + let _temp_683 = 0; + let _temp_684 = 0; + let _temp_685 = 0; + let _temp_686 = 0; + let _temp_687 = 0; + let _temp_688 = 0; + let _temp_689 = 0; + let _temp_690 = 0; + let _temp_691 = 0; + let _temp_692 = 0; + let _temp_693 = 0; + let _temp_694 = 0; + let _temp_695 = 0; + let _temp_696 = 0; + let _temp_697 = 0; + let _temp_698 = 0; + let _temp_699 = 0; + let _temp_700 = 0; + let _temp_701 = 0; + let _temp_702 = 0; + let _temp_703 = 0; + let _temp_704 = 0; + let _temp_705 = 0; + let _temp_706 = 0; + let _temp_707 = 0; + let _temp_708 = 0; + let _temp_709 = 0; + let _temp_710 = 0; + let _temp_711 = 0; + let _temp_712 = 0; + let _temp_713 = 0; + let _temp_714 = 0; + let _temp_715 = 0; + let _temp_716 = 0; + let _temp_717 = 0; + let _temp_718 = 0; + let _temp_719 = 0; + let _temp_720 = 0; + let _temp_721 = 0; + let _temp_722 = 0; + let _temp_723 = 0; + let _temp_724 = 0; + let _temp_725 = 0; + let _temp_726 = 0; + let _temp_727 = 0; + let _temp_728 = 0; + let _temp_729 = 0; + let _temp_730 = 0; + let _temp_731 = 0; + let _temp_732 = 0; + let _temp_733 = 0; + let _temp_734 = 0; + let _temp_735 = 0; + let _temp_736 = 0; + let _temp_737 = 0; + let _temp_738 = 0; + let _temp_739 = 0; + let _temp_740 = 0; + let _temp_741 = 0; + let _temp_742 = 0; + let _temp_743 = 0; + let _temp_744 = 0; + let _temp_745 = 0; + let _temp_746 = 0; + let _temp_747 = 0; + let _temp_748 = 0; + let _temp_749 = 0; + let _temp_750 = 0; + let _temp_751 = 0; + let _temp_752 = 0; + let _temp_753 = 0; + let _temp_754 = 0; + let _temp_755 = 0; + let _temp_756 = 0; + let _temp_757 = 0; + let _temp_758 = 0; + let _temp_759 = 0; + let _temp_760 = 0; + let _temp_761 = 0; + let _temp_762 = 0; + let _temp_763 = 0; + let _temp_764 = 0; + let _temp_765 = 0; + let _temp_766 = 0; + let _temp_767 = 0; + let _temp_768 = 0; + let _temp_769 = 0; + let _temp_770 = 0; + let _temp_771 = 0; + let _temp_772 = 0; + let _temp_773 = 0; + let _temp_774 = 0; + let _temp_775 = 0; + let _temp_776 = 0; + let _temp_777 = 0; + let _temp_778 = 0; + let _temp_779 = 0; + let _temp_780 = 0; + let _temp_781 = 0; + let _temp_782 = 0; + let _temp_783 = 0; + let _temp_784 = 0; + let _temp_785 = 0; + let _temp_786 = 0; + let _temp_787 = 0; + let _temp_788 = 0; + let _temp_789 = 0; + let _temp_790 = 0; + let _temp_791 = 0; + let _temp_792 = 0; + let _temp_793 = 0; + let _temp_794 = 0; + let _temp_795 = 0; + let _temp_796 = 0; + let _temp_797 = 0; + let _temp_798 = 0; + let _temp_799 = 0; + let _temp_800 = 0; + let _temp_801 = 0; + let _temp_802 = 0; + let _temp_803 = 0; + let _temp_804 = 0; + let _temp_805 = 0; + let _temp_806 = 0; + let _temp_807 = 0; + let _temp_808 = 0; + let _temp_809 = 0; + let _temp_810 = 0; + let _temp_811 = 0; + let _temp_812 = 0; + let _temp_813 = 0; + let _temp_814 = 0; + let _temp_815 = 0; + let _temp_816 = 0; + let _temp_817 = 0; + let _temp_818 = 0; + let _temp_819 = 0; + let _temp_820 = 0; + let _temp_821 = 0; + let _temp_822 = 0; + let _temp_823 = 0; + let _temp_824 = 0; + let _temp_825 = 0; + let _temp_826 = 0; + let _temp_827 = 0; + let _temp_828 = 0; + let _temp_829 = 0; + let _temp_830 = 0; + let _temp_831 = 0; + let _temp_832 = 0; + let _temp_833 = 0; + let _temp_834 = 0; + let _temp_835 = 0; + let _temp_836 = 0; + let _temp_837 = 0; + let _temp_838 = 0; + let _temp_839 = 0; + let _temp_840 = 0; + let _temp_841 = 0; + let _temp_842 = 0; + let _temp_843 = 0; + let _temp_844 = 0; + let _temp_845 = 0; + let _temp_846 = 0; + let _temp_847 = 0; + let _temp_848 = 0; + let _temp_849 = 0; + let _temp_850 = 0; + let _temp_851 = 0; + let _temp_852 = 0; + let _temp_853 = 0; + let _temp_854 = 0; + let _temp_855 = 0; + let _temp_856 = 0; + let _temp_857 = 0; + let _temp_858 = 0; + let _temp_859 = 0; + let _temp_860 = 0; + let _temp_861 = 0; + let _temp_862 = 0; + let _temp_863 = 0; + let _temp_864 = 0; + let _temp_865 = 0; + let _temp_866 = 0; + let _temp_867 = 0; + let _temp_868 = 0; + let _temp_869 = 0; + let _temp_870 = 0; + let _temp_871 = 0; + let _temp_872 = 0; + let _temp_873 = 0; + let _temp_874 = 0; + let _temp_875 = 0; + let _temp_876 = 0; + let _temp_877 = 0; + let _temp_878 = 0; + let _temp_879 = 0; + let _temp_880 = 0; + let _temp_881 = 0; + let _temp_882 = 0; + let _temp_883 = 0; + let _temp_884 = 0; + let _temp_885 = 0; + let _temp_886 = 0; + let _temp_887 = 0; + let _temp_888 = 0; + let _temp_889 = 0; + let _temp_890 = 0; + let _temp_891 = 0; + let _temp_892 = 0; + let _temp_893 = 0; + let _temp_894 = 0; + let _temp_895 = 0; + let _temp_896 = 0; + let _temp_897 = 0; + let _temp_898 = 0; + let _temp_899 = 0; + let _temp_900 = 0; + let _temp_901 = 0; + let _temp_902 = 0; + let _temp_903 = 0; + let _temp_904 = 0; + let _temp_905 = 0; + let _temp_906 = 0; + let _temp_907 = 0; + let _temp_908 = 0; + let _temp_909 = 0; + let _temp_910 = 0; + let _temp_911 = 0; + let _temp_912 = 0; + let _temp_913 = 0; + let _temp_914 = 0; + let _temp_915 = 0; + let _temp_916 = 0; + let _temp_917 = 0; + let _temp_918 = 0; + let _temp_919 = 0; + let _temp_920 = 0; + let _temp_921 = 0; + let _temp_922 = 0; + let _temp_923 = 0; + let _temp_924 = 0; + let _temp_925 = 0; + let _temp_926 = 0; + let _temp_927 = 0; + let _temp_928 = 0; + let _temp_929 = 0; + let _temp_930 = 0; + let _temp_931 = 0; + let _temp_932 = 0; + let _temp_933 = 0; + let _temp_934 = 0; + let _temp_935 = 0; + let _temp_936 = 0; + let _temp_937 = 0; + let _temp_938 = 0; + let _temp_939 = 0; + let _temp_940 = 0; + let _temp_941 = 0; + let _temp_942 = 0; + let _temp_943 = 0; + let _temp_944 = 0; + let _temp_945 = 0; + let _temp_946 = 0; + let _temp_947 = 0; + let _temp_948 = 0; + let _temp_949 = 0; + let _temp_950 = 0; + let _temp_951 = 0; + let _temp_952 = 0; + let _temp_953 = 0; + let _temp_954 = 0; + let _temp_955 = 0; + let _temp_956 = 0; + let _temp_957 = 0; + let _temp_958 = 0; + let _temp_959 = 0; + let _temp_960 = 0; + let _temp_961 = 0; + let _temp_962 = 0; + let _temp_963 = 0; + let _temp_964 = 0; + let _temp_965 = 0; + let _temp_966 = 0; + let _temp_967 = 0; + let _temp_968 = 0; + let _temp_969 = 0; + let _temp_970 = 0; + let _temp_971 = 0; + let _temp_972 = 0; + let _temp_973 = 0; + let _temp_974 = 0; + let _temp_975 = 0; + let _temp_976 = 0; + let _temp_977 = 0; + let _temp_978 = 0; + let _temp_979 = 0; + let _temp_980 = 0; + let _temp_981 = 0; + let _temp_982 = 0; + let _temp_983 = 0; + let _temp_984 = 0; + let _temp_985 = 0; + let _temp_986 = 0; + let _temp_987 = 0; + let _temp_988 = 0; + let _temp_989 = 0; + let _temp_990 = 0; + let _temp_991 = 0; + let _temp_992 = 0; + let _temp_993 = 0; + let _temp_994 = 0; + let _temp_995 = 0; + let _temp_996 = 0; + let _temp_997 = 0; + let _temp_998 = 0; + let _temp_999 = 0; + let _temp_1000 = 0; + let _temp_1001 = 0; + let _temp_1002 = 0; + let _temp_1003 = 0; + let _temp_1004 = 0; + let _temp_1005 = 0; + let _temp_1006 = 0; + let _temp_1007 = 0; + let _temp_1008 = 0; + let _temp_1009 = 0; + let _temp_1010 = 0; + let _temp_1011 = 0; + let _temp_1012 = 0; + let _temp_1013 = 0; + let _temp_1014 = 0; + let _temp_1015 = 0; + let _temp_1016 = 0; + let _temp_1017 = 0; + let _temp_1018 = 0; + let _temp_1019 = 0; + let _temp_1020 = 0; + let _temp_1021 = 0; + let _temp_1022 = 0; + let _temp_1023 = 0; + let _temp_1024 = 0; + let _temp_1025 = 0; + let _temp_1026 = 0; + let _temp_1027 = 0; + let _temp_1028 = 0; + let _temp_1029 = 0; + let _temp_1030 = 0; + let _temp_1031 = 0; + let _temp_1032 = 0; + let _temp_1033 = 0; + let _temp_1034 = 0; + let _temp_1035 = 0; + let _temp_1036 = 0; + let _temp_1037 = 0; + let _temp_1038 = 0; + let _temp_1039 = 0; + let _temp_1040 = 0; + let _temp_1041 = 0; + let _temp_1042 = 0; + let _temp_1043 = 0; + let _temp_1044 = 0; + let _temp_1045 = 0; + let _temp_1046 = 0; + let _temp_1047 = 0; + let _temp_1048 = 0; + let _temp_1049 = 0; + let _temp_1050 = 0; + let _temp_1051 = 0; + let _temp_1052 = 0; + let _temp_1053 = 0; + let _temp_1054 = 0; + let _temp_1055 = 0; + let _temp_1056 = 0; + let _temp_1057 = 0; + let _temp_1058 = 0; + let _temp_1059 = 0; + let _temp_1060 = 0; + let _temp_1061 = 0; + let _temp_1062 = 0; + let _temp_1063 = 0; + let _temp_1064 = 0; + let _temp_1065 = 0; + let _temp_1066 = 0; + let _temp_1067 = 0; + let _temp_1068 = 0; + let _temp_1069 = 0; + let _temp_1070 = 0; + let _temp_1071 = 0; + let _temp_1072 = 0; + let _temp_1073 = 0; + let _temp_1074 = 0; + let _temp_1075 = 0; + let _temp_1076 = 0; + let _temp_1077 = 0; + let _temp_1078 = 0; + let _temp_1079 = 0; + let _temp_1080 = 0; + let _temp_1081 = 0; + let _temp_1082 = 0; + let _temp_1083 = 0; + let _temp_1084 = 0; + let _temp_1085 = 0; + let _temp_1086 = 0; + let _temp_1087 = 0; + let _temp_1088 = 0; + let _temp_1089 = 0; + let _temp_1090 = 0; + let _temp_1091 = 0; + let _temp_1092 = 0; + let _temp_1093 = 0; + let _temp_1094 = 0; + let _temp_1095 = 0; + let _temp_1096 = 0; + let _temp_1097 = 0; + let _temp_1098 = 0; + let _temp_1099 = 0; + let _temp_1100 = 0; + let _temp_1101 = 0; + let _temp_1102 = 0; + let _temp_1103 = 0; + let _temp_1104 = 0; + let _temp_1105 = 0; + let _temp_1106 = 0; + let _temp_1107 = 0; + let _temp_1108 = 0; + let _temp_1109 = 0; + let _temp_1110 = 0; + let _temp_1111 = 0; + let _temp_1112 = 0; + let _temp_1113 = 0; + let _temp_1114 = 0; + let _temp_1115 = 0; + let _temp_1116 = 0; + let _temp_1117 = 0; + let _temp_1118 = 0; + let _temp_1119 = 0; + let _temp_1120 = 0; + let _temp_1121 = 0; + let _temp_1122 = 0; + let _temp_1123 = 0; + let _temp_1124 = 0; + let _temp_1125 = 0; + let _temp_1126 = 0; + let _temp_1127 = 0; + let _temp_1128 = 0; + let _temp_1129 = 0; + let _temp_1130 = 0; + let _temp_1131 = 0; + let _temp_1132 = 0; + let _temp_1133 = 0; + let _temp_1134 = 0; + let _temp_1135 = 0; + let _temp_1136 = 0; + let _temp_1137 = 0; + let _temp_1138 = 0; + let _temp_1139 = 0; + let _temp_1140 = 0; + let _temp_1141 = 0; + let _temp_1142 = 0; + let _temp_1143 = 0; + let _temp_1144 = 0; + let _temp_1145 = 0; + let _temp_1146 = 0; + let _temp_1147 = 0; + let _temp_1148 = 0; + let _temp_1149 = 0; + let _temp_1150 = 0; + let _temp_1151 = 0; + let _temp_1152 = 0; + let _temp_1153 = 0; + let _temp_1154 = 0; + let _temp_1155 = 0; + let _temp_1156 = 0; + let _temp_1157 = 0; + let _temp_1158 = 0; + let _temp_1159 = 0; + let _temp_1160 = 0; + let _temp_1161 = 0; + let _temp_1162 = 0; + let _temp_1163 = 0; + let _temp_1164 = 0; + let _temp_1165 = 0; + let _temp_1166 = 0; + let _temp_1167 = 0; + let _temp_1168 = 0; + let _temp_1169 = 0; + let _temp_1170 = 0; + let _temp_1171 = 0; + let _temp_1172 = 0; + let _temp_1173 = 0; + let _temp_1174 = 0; + let _temp_1175 = 0; + let _temp_1176 = 0; + let _temp_1177 = 0; + let _temp_1178 = 0; + let _temp_1179 = 0; + let _temp_1180 = 0; + let _temp_1181 = 0; + let _temp_1182 = 0; + let _temp_1183 = 0; + let _temp_1184 = 0; + let _temp_1185 = 0; + let _temp_1186 = 0; + let _temp_1187 = 0; + let _temp_1188 = 0; + let _temp_1189 = 0; + let _temp_1190 = 0; + let _temp_1191 = 0; + let _temp_1192 = 0; + let _temp_1193 = 0; + let _temp_1194 = 0; + let _temp_1195 = 0; + let _temp_1196 = 0; + let _temp_1197 = 0; + let _temp_1198 = 0; + let _temp_1199 = 0; + let _temp_1200 = 0; + let _temp_1201 = 0; + let _temp_1202 = 0; + let _temp_1203 = 0; + let _temp_1204 = 0; + let _temp_1205 = 0; + let _temp_1206 = 0; + let _temp_1207 = 0; + let _temp_1208 = 0; + let _temp_1209 = 0; + let _temp_1210 = 0; + let _temp_1211 = 0; + let _temp_1212 = 0; + let _temp_1213 = 0; + let _temp_1214 = 0; + let _temp_1215 = 0; + let _temp_1216 = 0; + let _temp_1217 = 0; + let _temp_1218 = 0; + let _temp_1219 = 0; + let _temp_1220 = 0; + let _temp_1221 = 0; + let _temp_1222 = 0; + let _temp_1223 = 0; + let _temp_1224 = 0; + let _temp_1225 = 0; + let _temp_1226 = 0; + let _temp_1227 = 0; + let _temp_1228 = 0; + let _temp_1229 = 0; + let _temp_1230 = 0; + let _temp_1231 = 0; + let _temp_1232 = 0; + let _temp_1233 = 0; + let _temp_1234 = 0; + let _temp_1235 = 0; + let _temp_1236 = 0; + let _temp_1237 = 0; + let _temp_1238 = 0; + let _temp_1239 = 0; + let _temp_1240 = 0; + let _temp_1241 = 0; + let _temp_1242 = 0; + let _temp_1243 = 0; + let _temp_1244 = 0; + let _temp_1245 = 0; + let _temp_1246 = 0; + let _temp_1247 = 0; + let _temp_1248 = 0; + let _temp_1249 = 0; + let _temp_1250 = 0; + let _temp_1251 = 0; + let _temp_1252 = 0; + let _temp_1253 = 0; + let _temp_1254 = 0; + let _temp_1255 = 0; + let _temp_1256 = 0; + let _temp_1257 = 0; + let _temp_1258 = 0; + let _temp_1259 = 0; + let _temp_1260 = 0; + let _temp_1261 = 0; + let _temp_1262 = 0; + let _temp_1263 = 0; + let _temp_1264 = 0; + let _temp_1265 = 0; + let _temp_1266 = 0; + let _temp_1267 = 0; + let _temp_1268 = 0; + let _temp_1269 = 0; + let _temp_1270 = 0; + let _temp_1271 = 0; + let _temp_1272 = 0; + let _temp_1273 = 0; + let _temp_1274 = 0; + let _temp_1275 = 0; + let _temp_1276 = 0; + let _temp_1277 = 0; + let _temp_1278 = 0; + let _temp_1279 = 0; + let _temp_1280 = 0; + let _temp_1281 = 0; + let _temp_1282 = 0; + let _temp_1283 = 0; + let _temp_1284 = 0; + let _temp_1285 = 0; + let _temp_1286 = 0; + let _temp_1287 = 0; + let _temp_1288 = 0; + let _temp_1289 = 0; + let _temp_1290 = 0; + let _temp_1291 = 0; + let _temp_1292 = 0; + let _temp_1293 = 0; + let _temp_1294 = 0; + let _temp_1295 = 0; + let _temp_1296 = 0; + let _temp_1297 = 0; + let _temp_1298 = 0; + let _temp_1299 = 0; + let _temp_1300 = 0; + let _temp_1301 = 0; + let _temp_1302 = 0; + let _temp_1303 = 0; + let _temp_1304 = 0; + let _temp_1305 = 0; + let _temp_1306 = 0; + let _temp_1307 = 0; + let _temp_1308 = 0; + let _temp_1309 = 0; + let _temp_1310 = 0; + let _temp_1311 = 0; + let _temp_1312 = 0; + let _temp_1313 = 0; + let _temp_1314 = 0; + let _temp_1315 = 0; + let _temp_1316 = 0; + let _temp_1317 = 0; + let _temp_1318 = 0; + let _temp_1319 = 0; + let _temp_1320 = 0; + let _temp_1321 = 0; + let _temp_1322 = 0; + let _temp_1323 = 0; + let _temp_1324 = 0; + let _temp_1325 = 0; + let _temp_1326 = 0; + let _temp_1327 = 0; + let _temp_1328 = 0; + let _temp_1329 = 0; + let _temp_1330 = 0; + let _temp_1331 = 0; + let _temp_1332 = 0; + let _temp_1333 = 0; + let _temp_1334 = 0; + let _temp_1335 = 0; + let _temp_1336 = 0; + let _temp_1337 = 0; + let _temp_1338 = 0; + let _temp_1339 = 0; + let _temp_1340 = 0; + let _temp_1341 = 0; + let _temp_1342 = 0; + let _temp_1343 = 0; + let _temp_1344 = 0; + let _temp_1345 = 0; + let _temp_1346 = 0; + let _temp_1347 = 0; + let _temp_1348 = 0; + let _temp_1349 = 0; + let _temp_1350 = 0; + let _temp_1351 = 0; + let _temp_1352 = 0; + let _temp_1353 = 0; + let _temp_1354 = 0; + let _temp_1355 = 0; + let _temp_1356 = 0; + let _temp_1357 = 0; + let _temp_1358 = 0; + let _temp_1359 = 0; + let _temp_1360 = 0; + let _temp_1361 = 0; + let _temp_1362 = 0; + let _temp_1363 = 0; + let _temp_1364 = 0; + let _temp_1365 = 0; + let _temp_1366 = 0; + let _temp_1367 = 0; + let _temp_1368 = 0; + let _temp_1369 = 0; + let _temp_1370 = 0; + let _temp_1371 = 0; + let _temp_1372 = 0; + let _temp_1373 = 0; + let _temp_1374 = 0; + let _temp_1375 = 0; + let _temp_1376 = 0; + let _temp_1377 = 0; + let _temp_1378 = 0; + let _temp_1379 = 0; + let _temp_1380 = 0; + let _temp_1381 = 0; + let _temp_1382 = 0; + let _temp_1383 = 0; + let _temp_1384 = 0; + let _temp_1385 = 0; + let _temp_1386 = 0; + let _temp_1387 = 0; + let _temp_1388 = 0; + let _temp_1389 = 0; + let _temp_1390 = 0; + let _temp_1391 = 0; + let _temp_1392 = 0; + let _temp_1393 = 0; + let _temp_1394 = 0; + let _temp_1395 = 0; + let _temp_1396 = 0; + let _temp_1397 = 0; + let _temp_1398 = 0; + let _temp_1399 = 0; + let _temp_1400 = 0; + let _temp_1401 = 0; + let _temp_1402 = 0; + let _temp_1403 = 0; + let _temp_1404 = 0; + let _temp_1405 = 0; + let _temp_1406 = 0; + let _temp_1407 = 0; + let _temp_1408 = 0; + let _temp_1409 = 0; + let _temp_1410 = 0; + let _temp_1411 = 0; + let _temp_1412 = 0; + let _temp_1413 = 0; + let _temp_1414 = 0; + let _temp_1415 = 0; + let _temp_1416 = 0; + let _temp_1417 = 0; + let _temp_1418 = 0; + let _temp_1419 = 0; + let _temp_1420 = 0; + let _temp_1421 = 0; + let _temp_1422 = 0; + let _temp_1423 = 0; + let _temp_1424 = 0; + let _temp_1425 = 0; + let _temp_1426 = 0; + let _temp_1427 = 0; + let _temp_1428 = 0; + let _temp_1429 = 0; + let _temp_1430 = 0; + let _temp_1431 = 0; + let _temp_1432 = 0; + let _temp_1433 = 0; + let _temp_1434 = 0; + let _temp_1435 = 0; + let _temp_1436 = 0; + let _temp_1437 = 0; + let _temp_1438 = 0; + let _temp_1439 = 0; + let _temp_1440 = 0; + let _temp_1441 = 0; + let _temp_1442 = 0; + let _temp_1443 = 0; + let _temp_1444 = 0; + let _temp_1445 = 0; + let _temp_1446 = 0; + let _temp_1447 = 0; + let _temp_1448 = 0; + let _temp_1449 = 0; + let _temp_1450 = 0; + let _temp_1451 = 0; + let _temp_1452 = 0; + let _temp_1453 = 0; + let _temp_1454 = 0; + let _temp_1455 = 0; + let _temp_1456 = 0; + let _temp_1457 = 0; + let _temp_1458 = 0; + let _temp_1459 = 0; + let _temp_1460 = 0; + let _temp_1461 = 0; + let _temp_1462 = 0; + let _temp_1463 = 0; + let _temp_1464 = 0; + let _temp_1465 = 0; + let _temp_1466 = 0; + let _temp_1467 = 0; + let _temp_1468 = 0; + let _temp_1469 = 0; + let _temp_1470 = 0; + let _temp_1471 = 0; + let _temp_1472 = 0; + let _temp_1473 = 0; + let _temp_1474 = 0; + let _temp_1475 = 0; + let _temp_1476 = 0; + let _temp_1477 = 0; + let _temp_1478 = 0; + let _temp_1479 = 0; + let _temp_1480 = 0; + let _temp_1481 = 0; + let _temp_1482 = 0; + let _temp_1483 = 0; + let _temp_1484 = 0; + let _temp_1485 = 0; + let _temp_1486 = 0; + let _temp_1487 = 0; + let _temp_1488 = 0; + let _temp_1489 = 0; + let _temp_1490 = 0; + let _temp_1491 = 0; + let _temp_1492 = 0; + let _temp_1493 = 0; + let _temp_1494 = 0; + let _temp_1495 = 0; + let _temp_1496 = 0; + let _temp_1497 = 0; + let _temp_1498 = 0; + let _temp_1499 = 0; + let _temp_1500 = 0; + let _temp_1501 = 0; + let _temp_1502 = 0; + let _temp_1503 = 0; + let _temp_1504 = 0; + let _temp_1505 = 0; + let _temp_1506 = 0; + let _temp_1507 = 0; + let _temp_1508 = 0; + let _temp_1509 = 0; + let _temp_1510 = 0; + let _temp_1511 = 0; + let _temp_1512 = 0; + let _temp_1513 = 0; + let _temp_1514 = 0; + let _temp_1515 = 0; + let _temp_1516 = 0; + let _temp_1517 = 0; + let _temp_1518 = 0; + let _temp_1519 = 0; + let _temp_1520 = 0; + let _temp_1521 = 0; + let _temp_1522 = 0; + let _temp_1523 = 0; + let _temp_1524 = 0; + let _temp_1525 = 0; + let _temp_1526 = 0; + let _temp_1527 = 0; + let _temp_1528 = 0; + let _temp_1529 = 0; + let _temp_1530 = 0; + let _temp_1531 = 0; + let _temp_1532 = 0; + let _temp_1533 = 0; + let _temp_1534 = 0; + let _temp_1535 = 0; + let _temp_1536 = 0; + let _temp_1537 = 0; + let _temp_1538 = 0; + let _temp_1539 = 0; + let _temp_1540 = 0; + let _temp_1541 = 0; + let _temp_1542 = 0; + let _temp_1543 = 0; + let _temp_1544 = 0; + let _temp_1545 = 0; + let _temp_1546 = 0; + let _temp_1547 = 0; + let _temp_1548 = 0; + let _temp_1549 = 0; + let _temp_1550 = 0; + let _temp_1551 = 0; + let _temp_1552 = 0; + let _temp_1553 = 0; + let _temp_1554 = 0; + let _temp_1555 = 0; + let _temp_1556 = 0; + let _temp_1557 = 0; + let _temp_1558 = 0; + let _temp_1559 = 0; + let _temp_1560 = 0; + let _temp_1561 = 0; + let _temp_1562 = 0; + let _temp_1563 = 0; + let _temp_1564 = 0; + let _temp_1565 = 0; + let _temp_1566 = 0; + let _temp_1567 = 0; + let _temp_1568 = 0; + let _temp_1569 = 0; + let _temp_1570 = 0; + let _temp_1571 = 0; + let _temp_1572 = 0; + let _temp_1573 = 0; + let _temp_1574 = 0; + let _temp_1575 = 0; + let _temp_1576 = 0; + let _temp_1577 = 0; + let _temp_1578 = 0; + let _temp_1579 = 0; + let _temp_1580 = 0; + let _temp_1581 = 0; + let _temp_1582 = 0; + let _temp_1583 = 0; + let _temp_1584 = 0; + let _temp_1585 = 0; + let _temp_1586 = 0; + let _temp_1587 = 0; + let _temp_1588 = 0; + let _temp_1589 = 0; + let _temp_1590 = 0; + let _temp_1591 = 0; + let _temp_1592 = 0; + let _temp_1593 = 0; + let _temp_1594 = 0; + let _temp_1595 = 0; + let _temp_1596 = 0; + let _temp_1597 = 0; + let _temp_1598 = 0; + let _temp_1599 = 0; + let _temp_1600 = 0; + let _temp_1601 = 0; + let _temp_1602 = 0; + let _temp_1603 = 0; + let _temp_1604 = 0; + let _temp_1605 = 0; + let _temp_1606 = 0; + let _temp_1607 = 0; + let _temp_1608 = 0; + let _temp_1609 = 0; + let _temp_1610 = 0; + let _temp_1611 = 0; + let _temp_1612 = 0; + let _temp_1613 = 0; + let _temp_1614 = 0; + let _temp_1615 = 0; + let _temp_1616 = 0; + let _temp_1617 = 0; + let _temp_1618 = 0; + let _temp_1619 = 0; + let _temp_1620 = 0; + let _temp_1621 = 0; + let _temp_1622 = 0; + let _temp_1623 = 0; + let _temp_1624 = 0; + let _temp_1625 = 0; + let _temp_1626 = 0; + let _temp_1627 = 0; + let _temp_1628 = 0; + let _temp_1629 = 0; + let _temp_1630 = 0; + let _temp_1631 = 0; + let _temp_1632 = 0; + let _temp_1633 = 0; + let _temp_1634 = 0; + let _temp_1635 = 0; + let _temp_1636 = 0; + let _temp_1637 = 0; + let _temp_1638 = 0; + let _temp_1639 = 0; + let _temp_1640 = 0; + let _temp_1641 = 0; + let _temp_1642 = 0; + let _temp_1643 = 0; + let _temp_1644 = 0; + let _temp_1645 = 0; + let _temp_1646 = 0; + let _temp_1647 = 0; + let _temp_1648 = 0; + let _temp_1649 = 0; + let _temp_1650 = 0; + let _temp_1651 = 0; + let _temp_1652 = 0; + let _temp_1653 = 0; + let _temp_1654 = 0; + let _temp_1655 = 0; + let _temp_1656 = 0; + let _temp_1657 = 0; + let _temp_1658 = 0; + let _temp_1659 = 0; + let _temp_1660 = 0; + let _temp_1661 = 0; + let _temp_1662 = 0; + let _temp_1663 = 0; + let _temp_1664 = 0; + let _temp_1665 = 0; + let _temp_1666 = 0; + let _temp_1667 = 0; + let _temp_1668 = 0; + let _temp_1669 = 0; + let _temp_1670 = 0; + let _temp_1671 = 0; + let _temp_1672 = 0; + let _temp_1673 = 0; + let _temp_1674 = 0; + let _temp_1675 = 0; + let _temp_1676 = 0; + let _temp_1677 = 0; + let _temp_1678 = 0; + let _temp_1679 = 0; + let _temp_1680 = 0; + let _temp_1681 = 0; + let _temp_1682 = 0; + let _temp_1683 = 0; + let _temp_1684 = 0; + let _temp_1685 = 0; + let _temp_1686 = 0; + let _temp_1687 = 0; + let _temp_1688 = 0; + let _temp_1689 = 0; + let _temp_1690 = 0; + let _temp_1691 = 0; + let _temp_1692 = 0; + let _temp_1693 = 0; + let _temp_1694 = 0; + let _temp_1695 = 0; + let _temp_1696 = 0; + let _temp_1697 = 0; + let _temp_1698 = 0; + let _temp_1699 = 0; + let _temp_1700 = 0; + let _temp_1701 = 0; + let _temp_1702 = 0; + let _temp_1703 = 0; + let _temp_1704 = 0; + let _temp_1705 = 0; + let _temp_1706 = 0; + let _temp_1707 = 0; + let _temp_1708 = 0; + let _temp_1709 = 0; + let _temp_1710 = 0; + let _temp_1711 = 0; + let _temp_1712 = 0; + let _temp_1713 = 0; + let _temp_1714 = 0; + let _temp_1715 = 0; + let _temp_1716 = 0; + let _temp_1717 = 0; + let _temp_1718 = 0; + let _temp_1719 = 0; + let _temp_1720 = 0; + let _temp_1721 = 0; + let _temp_1722 = 0; + let _temp_1723 = 0; + let _temp_1724 = 0; + let _temp_1725 = 0; + let _temp_1726 = 0; + let _temp_1727 = 0; + let _temp_1728 = 0; + let _temp_1729 = 0; + let _temp_1730 = 0; + let _temp_1731 = 0; + let _temp_1732 = 0; + let _temp_1733 = 0; + let _temp_1734 = 0; + let _temp_1735 = 0; + let _temp_1736 = 0; + let _temp_1737 = 0; + let _temp_1738 = 0; + let _temp_1739 = 0; + let _temp_1740 = 0; + let _temp_1741 = 0; + let _temp_1742 = 0; + let _temp_1743 = 0; + let _temp_1744 = 0; + let _temp_1745 = 0; + let _temp_1746 = 0; + let _temp_1747 = 0; + let _temp_1748 = 0; + let _temp_1749 = 0; + let _temp_1750 = 0; + let _temp_1751 = 0; + let _temp_1752 = 0; + let _temp_1753 = 0; + let _temp_1754 = 0; + let _temp_1755 = 0; + let _temp_1756 = 0; + let _temp_1757 = 0; + let _temp_1758 = 0; + let _temp_1759 = 0; + let _temp_1760 = 0; + let _temp_1761 = 0; + let _temp_1762 = 0; + let _temp_1763 = 0; + let _temp_1764 = 0; + let _temp_1765 = 0; + let _temp_1766 = 0; + let _temp_1767 = 0; + let _temp_1768 = 0; + let _temp_1769 = 0; + let _temp_1770 = 0; + let _temp_1771 = 0; + let _temp_1772 = 0; + let _temp_1773 = 0; + let _temp_1774 = 0; + let _temp_1775 = 0; + let _temp_1776 = 0; + let _temp_1777 = 0; + let _temp_1778 = 0; + let _temp_1779 = 0; + let _temp_1780 = 0; + let _temp_1781 = 0; + let _temp_1782 = 0; + let _temp_1783 = 0; + let _temp_1784 = 0; + let _temp_1785 = 0; + let _temp_1786 = 0; + let _temp_1787 = 0; + let _temp_1788 = 0; + let _temp_1789 = 0; + let _temp_1790 = 0; + let _temp_1791 = 0; + let _temp_1792 = 0; + let _temp_1793 = 0; + let _temp_1794 = 0; + let _temp_1795 = 0; + let _temp_1796 = 0; + let _temp_1797 = 0; + let _temp_1798 = 0; + let _temp_1799 = 0; + let _temp_1800 = 0; + let _temp_1801 = 0; + let _temp_1802 = 0; + let _temp_1803 = 0; + let _temp_1804 = 0; + let _temp_1805 = 0; + let _temp_1806 = 0; + let _temp_1807 = 0; + let _temp_1808 = 0; + let _temp_1809 = 0; + let _temp_1810 = 0; + let _temp_1811 = 0; + let _temp_1812 = 0; + let _temp_1813 = 0; + let _temp_1814 = 0; + let _temp_1815 = 0; + let _temp_1816 = 0; + let _temp_1817 = 0; + let _temp_1818 = 0; + let _temp_1819 = 0; + let _temp_1820 = 0; + let _temp_1821 = 0; + let _temp_1822 = 0; + let _temp_1823 = 0; + let _temp_1824 = 0; + let _temp_1825 = 0; + let _temp_1826 = 0; + let _temp_1827 = 0; + let _temp_1828 = 0; + let _temp_1829 = 0; + let _temp_1830 = 0; + let _temp_1831 = 0; + let _temp_1832 = 0; + let _temp_1833 = 0; + let _temp_1834 = 0; + let _temp_1835 = 0; + let _temp_1836 = 0; + let _temp_1837 = 0; + let _temp_1838 = 0; + let _temp_1839 = 0; + let _temp_1840 = 0; + let _temp_1841 = 0; + let _temp_1842 = 0; + let _temp_1843 = 0; + let _temp_1844 = 0; + let _temp_1845 = 0; + let _temp_1846 = 0; + let _temp_1847 = 0; + let _temp_1848 = 0; + let _temp_1849 = 0; + let _temp_1850 = 0; + let _temp_1851 = 0; + let _temp_1852 = 0; + let _temp_1853 = 0; + let _temp_1854 = 0; + let _temp_1855 = 0; + let _temp_1856 = 0; + let _temp_1857 = 0; + let _temp_1858 = 0; + let _temp_1859 = 0; + let _temp_1860 = 0; + let _temp_1861 = 0; + let _temp_1862 = 0; + let _temp_1863 = 0; + let _temp_1864 = 0; + let _temp_1865 = 0; + let _temp_1866 = 0; + let _temp_1867 = 0; + let _temp_1868 = 0; + let _temp_1869 = 0; + let _temp_1870 = 0; + let _temp_1871 = 0; + let _temp_1872 = 0; + let _temp_1873 = 0; + let _temp_1874 = 0; + let _temp_1875 = 0; + let _temp_1876 = 0; + let _temp_1877 = 0; + let _temp_1878 = 0; + let _temp_1879 = 0; + let _temp_1880 = 0; + let _temp_1881 = 0; + let _temp_1882 = 0; + let _temp_1883 = 0; + let _temp_1884 = 0; + let _temp_1885 = 0; + let _temp_1886 = 0; + let _temp_1887 = 0; + let _temp_1888 = 0; + let _temp_1889 = 0; + let _temp_1890 = 0; + let _temp_1891 = 0; + let _temp_1892 = 0; + let _temp_1893 = 0; + let _temp_1894 = 0; + let _temp_1895 = 0; + let _temp_1896 = 0; + let _temp_1897 = 0; + let _temp_1898 = 0; + let _temp_1899 = 0; + let _temp_1900 = 0; + let _temp_1901 = 0; + let _temp_1902 = 0; + let _temp_1903 = 0; + let _temp_1904 = 0; + let _temp_1905 = 0; + let _temp_1906 = 0; + let _temp_1907 = 0; + let _temp_1908 = 0; + let _temp_1909 = 0; + let _temp_1910 = 0; + let _temp_1911 = 0; + let _temp_1912 = 0; + let _temp_1913 = 0; + let _temp_1914 = 0; + let _temp_1915 = 0; + let _temp_1916 = 0; + let _temp_1917 = 0; + let _temp_1918 = 0; + let _temp_1919 = 0; + let _temp_1920 = 0; + let _temp_1921 = 0; + let _temp_1922 = 0; + let _temp_1923 = 0; + let _temp_1924 = 0; + let _temp_1925 = 0; + let _temp_1926 = 0; + let _temp_1927 = 0; + let _temp_1928 = 0; + let _temp_1929 = 0; + let _temp_1930 = 0; + let _temp_1931 = 0; + let _temp_1932 = 0; + let _temp_1933 = 0; + let _temp_1934 = 0; + let _temp_1935 = 0; + let _temp_1936 = 0; + let _temp_1937 = 0; + let _temp_1938 = 0; + let _temp_1939 = 0; + let _temp_1940 = 0; + let _temp_1941 = 0; + let _temp_1942 = 0; + let _temp_1943 = 0; + let _temp_1944 = 0; + let _temp_1945 = 0; + let _temp_1946 = 0; + let _temp_1947 = 0; + let _temp_1948 = 0; + let _temp_1949 = 0; + let _temp_1950 = 0; + let _temp_1951 = 0; + let _temp_1952 = 0; + let _temp_1953 = 0; + let _temp_1954 = 0; + let _temp_1955 = 0; + let _temp_1956 = 0; + let _temp_1957 = 0; + let _temp_1958 = 0; + let _temp_1959 = 0; + let _temp_1960 = 0; + let _temp_1961 = 0; + let _temp_1962 = 0; + let _temp_1963 = 0; + let _temp_1964 = 0; + let _temp_1965 = 0; + let _temp_1966 = 0; + let _temp_1967 = 0; + let _temp_1968 = 0; + let _temp_1969 = 0; + let _temp_1970 = 0; + let _temp_1971 = 0; + let _temp_1972 = 0; + let _temp_1973 = 0; + let _temp_1974 = 0; + let _temp_1975 = 0; + let _temp_1976 = 0; + let _temp_1977 = 0; + let _temp_1978 = 0; + let _temp_1979 = 0; + let _temp_1980 = 0; + let _temp_1981 = 0; + let _temp_1982 = 0; + let _temp_1983 = 0; + let _temp_1984 = 0; + let _temp_1985 = 0; + let _temp_1986 = 0; + let _temp_1987 = 0; + let _temp_1988 = 0; + let _temp_1989 = 0; + let _temp_1990 = 0; + let _temp_1991 = 0; + let _temp_1992 = 0; + let _temp_1993 = 0; + let _temp_1994 = 0; + let _temp_1995 = 0; + let _temp_1996 = 0; + let _temp_1997 = 0; + let _temp_1998 = 0; + let _temp_1999 = 0; + let _temp_2000 = 0; + let _temp_2001 = 0; + let _temp_2002 = 0; + let _temp_2003 = 0; + let _temp_2004 = 0; + let _temp_2005 = 0; + let _temp_2006 = 0; + let _temp_2007 = 0; + let _temp_2008 = 0; + let _temp_2009 = 0; + let _temp_2010 = 0; + let _temp_2011 = 0; + let _temp_2012 = 0; + let _temp_2013 = 0; + let _temp_2014 = 0; + let _temp_2015 = 0; + let _temp_2016 = 0; + let _temp_2017 = 0; + let _temp_2018 = 0; + let _temp_2019 = 0; + let _temp_2020 = 0; + let _temp_2021 = 0; + let _temp_2022 = 0; + let _temp_2023 = 0; + let _temp_2024 = 0; + let _temp_2025 = 0; + let _temp_2026 = 0; + let _temp_2027 = 0; + let _temp_2028 = 0; + let _temp_2029 = 0; + let _temp_2030 = 0; + let _temp_2031 = 0; + let _temp_2032 = 0; + let _temp_2033 = 0; + let _temp_2034 = 0; + let _temp_2035 = 0; + let _temp_2036 = 0; + let _temp_2037 = 0; + let _temp_2038 = 0; + let _temp_2039 = 0; + let _temp_2040 = 0; + let _temp_2041 = 0; + let _temp_2042 = 0; + let _temp_2043 = 0; + let _temp_2044 = 0; + let _temp_2045 = 0; + let _temp_2046 = 0; + let _temp_2047 = 0; + let _temp_2048 = 0; + let _temp_2049 = 0; + let _temp_2050 = 0; + let _temp_2051 = 0; + let _temp_2052 = 0; + let _temp_2053 = 0; + let _temp_2054 = 0; + let _temp_2055 = 0; + let _temp_2056 = 0; + let _temp_2057 = 0; + let _temp_2058 = 0; + let _temp_2059 = 0; + let _temp_2060 = 0; + let _temp_2061 = 0; + let _temp_2062 = 0; + let _temp_2063 = 0; + let _temp_2064 = 0; + let _temp_2065 = 0; + let _temp_2066 = 0; + let _temp_2067 = 0; + let _temp_2068 = 0; + let _temp_2069 = 0; + let _temp_2070 = 0; + let _temp_2071 = 0; + let _temp_2072 = 0; + let _temp_2073 = 0; + let _temp_2074 = 0; + let _temp_2075 = 0; + let _temp_2076 = 0; + let _temp_2077 = 0; + let _temp_2078 = 0; + let _temp_2079 = 0; + let _temp_2080 = 0; + let _temp_2081 = 0; + let _temp_2082 = 0; + let _temp_2083 = 0; + let _temp_2084 = 0; + let _temp_2085 = 0; + let _temp_2086 = 0; + let _temp_2087 = 0; + let _temp_2088 = 0; + let _temp_2089 = 0; + let _temp_2090 = 0; + let _temp_2091 = 0; + let _temp_2092 = 0; + let _temp_2093 = 0; + let _temp_2094 = 0; + let _temp_2095 = 0; + let _temp_2096 = 0; + let _temp_2097 = 0; + let _temp_2098 = 0; + let _temp_2099 = 0; + let _temp_2100 = 0; + let _temp_2101 = 0; + let _temp_2102 = 0; + let _temp_2103 = 0; + let _temp_2104 = 0; + let _temp_2105 = 0; + let _temp_2106 = 0; + let _temp_2107 = 0; + let _temp_2108 = 0; + let _temp_2109 = 0; + let _temp_2110 = 0; + let _temp_2111 = 0; + let _temp_2112 = 0; + let _temp_2113 = 0; + let _temp_2114 = 0; + let _temp_2115 = 0; + let _temp_2116 = 0; + let _temp_2117 = 0; + let _temp_2118 = 0; + let _temp_2119 = 0; + let _temp_2120 = 0; + let _temp_2121 = 0; + let _temp_2122 = 0; + let _temp_2123 = 0; + let _temp_2124 = 0; + let _temp_2125 = 0; + let _temp_2126 = 0; + let _temp_2127 = 0; + let _temp_2128 = 0; + let _temp_2129 = 0; + let _temp_2130 = 0; + let _temp_2131 = 0; + let _temp_2132 = 0; + let _temp_2133 = 0; + let _temp_2134 = 0; + let _temp_2135 = 0; + let _temp_2136 = 0; + let _temp_2137 = 0; + let _temp_2138 = 0; + let _temp_2139 = 0; + let _temp_2140 = 0; + let _temp_2141 = 0; + let _temp_2142 = 0; + let _temp_2143 = 0; + let _temp_2144 = 0; + let _temp_2145 = 0; + let _temp_2146 = 0; + let _temp_2147 = 0; + let _temp_2148 = 0; + let _temp_2149 = 0; + let _temp_2150 = 0; + let _temp_2151 = 0; + let _temp_2152 = 0; + let _temp_2153 = 0; + let _temp_2154 = 0; + let _temp_2155 = 0; + let _temp_2156 = 0; + let _temp_2157 = 0; + let _temp_2158 = 0; + let _temp_2159 = 0; + let _temp_2160 = 0; + let _temp_2161 = 0; + let _temp_2162 = 0; + let _temp_2163 = 0; + let _temp_2164 = 0; + let _temp_2165 = 0; + let _temp_2166 = 0; + let _temp_2167 = 0; + let _temp_2168 = 0; + let _temp_2169 = 0; + let _temp_2170 = 0; + let _temp_2171 = 0; + let _temp_2172 = 0; + let _temp_2173 = 0; + let _temp_2174 = 0; + let _temp_2175 = 0; + let _temp_2176 = 0; + let _temp_2177 = 0; + let _temp_2178 = 0; + let _temp_2179 = 0; + let _temp_2180 = 0; + let _temp_2181 = 0; + let _temp_2182 = 0; + let _temp_2183 = 0; + let _temp_2184 = 0; + let _temp_2185 = 0; + let _temp_2186 = 0; + let _temp_2187 = 0; + let _temp_2188 = 0; + let _temp_2189 = 0; + let _temp_2190 = 0; + let _temp_2191 = 0; + let _temp_2192 = 0; + let _temp_2193 = 0; + let _temp_2194 = 0; + let _temp_2195 = 0; + let _temp_2196 = 0; + let _temp_2197 = 0; + let _temp_2198 = 0; + let _temp_2199 = 0; + let _temp_2200 = 0; + let _temp_2201 = 0; + let _temp_2202 = 0; + let _temp_2203 = 0; + let _temp_2204 = 0; + let _temp_2205 = 0; + let _temp_2206 = 0; + let _temp_2207 = 0; + let _temp_2208 = 0; + let _temp_2209 = 0; + let _temp_2210 = 0; + let _temp_2211 = 0; + let _temp_2212 = 0; + let _temp_2213 = 0; + let _temp_2214 = 0; + let _temp_2215 = 0; + let _temp_2216 = 0; + let _temp_2217 = 0; + let _temp_2218 = 0; + let _temp_2219 = 0; + let _temp_2220 = 0; + let _temp_2221 = 0; + let _temp_2222 = 0; + let _temp_2223 = 0; + let _temp_2224 = 0; + let _temp_2225 = 0; + let _temp_2226 = 0; + let _temp_2227 = 0; + let _temp_2228 = 0; + let _temp_2229 = 0; + let _temp_2230 = 0; + let _temp_2231 = 0; + let _temp_2232 = 0; + let _temp_2233 = 0; + let _temp_2234 = 0; + let _temp_2235 = 0; + let _temp_2236 = 0; + let _temp_2237 = 0; + let _temp_2238 = 0; + let _temp_2239 = 0; + let _temp_2240 = 0; + let _temp_2241 = 0; + let _temp_2242 = 0; + let _temp_2243 = 0; + let _temp_2244 = 0; + let _temp_2245 = 0; + let _temp_2246 = 0; + let _temp_2247 = 0; + let _temp_2248 = 0; + let _temp_2249 = 0; + let _temp_2250 = 0; + let _temp_2251 = 0; + let _temp_2252 = 0; + let _temp_2253 = 0; + let _temp_2254 = 0; + let _temp_2255 = 0; + let _temp_2256 = 0; + let _temp_2257 = 0; + let _temp_2258 = 0; + let _temp_2259 = 0; + let _temp_2260 = 0; + let _temp_2261 = 0; + let _temp_2262 = 0; + let _temp_2263 = 0; + let _temp_2264 = 0; + let _temp_2265 = 0; + let _temp_2266 = 0; + let _temp_2267 = 0; + let _temp_2268 = 0; + let _temp_2269 = 0; + let _temp_2270 = 0; + let _temp_2271 = 0; + let _temp_2272 = 0; + let _temp_2273 = 0; + let _temp_2274 = 0; + let _temp_2275 = 0; + let _temp_2276 = 0; + let _temp_2277 = 0; + let _temp_2278 = 0; + let _temp_2279 = 0; + let _temp_2280 = 0; + let _temp_2281 = 0; + let _temp_2282 = 0; + let _temp_2283 = 0; + let _temp_2284 = 0; + let _temp_2285 = 0; + let _temp_2286 = 0; + let _temp_2287 = 0; + let _temp_2288 = 0; + let _temp_2289 = 0; + let _temp_2290 = 0; + let _temp_2291 = 0; + let _temp_2292 = 0; + let _temp_2293 = 0; + let _temp_2294 = 0; + let _temp_2295 = 0; + let _temp_2296 = 0; + let _temp_2297 = 0; + let _temp_2298 = 0; + let _temp_2299 = 0; + let _temp_2300 = 0; + let _temp_2301 = 0; + let _temp_2302 = 0; + let _temp_2303 = 0; + let _temp_2304 = 0; + let _temp_2305 = 0; + let _temp_2306 = 0; + let _temp_2307 = 0; + let _temp_2308 = 0; + let _temp_2309 = 0; + let _temp_2310 = 0; + let _temp_2311 = 0; + let _temp_2312 = 0; + let _temp_2313 = 0; + let _temp_2314 = 0; + let _temp_2315 = 0; + let _temp_2316 = 0; + let _temp_2317 = 0; + let _temp_2318 = 0; + let _temp_2319 = 0; + let _temp_2320 = 0; + let _temp_2321 = 0; + let _temp_2322 = 0; + let _temp_2323 = 0; + let _temp_2324 = 0; + let _temp_2325 = 0; + let _temp_2326 = 0; + let _temp_2327 = 0; + let _temp_2328 = 0; + let _temp_2329 = 0; + let _temp_2330 = 0; + let _temp_2331 = 0; + let _temp_2332 = 0; + let _temp_2333 = 0; + let _temp_2334 = 0; + let _temp_2335 = 0; + let _temp_2336 = 0; + let _temp_2337 = 0; + let _temp_2338 = 0; + let _temp_2339 = 0; + let _temp_2340 = 0; + let _temp_2341 = 0; + let _temp_2342 = 0; + let _temp_2343 = 0; + let _temp_2344 = 0; + let _temp_2345 = 0; + let _temp_2346 = 0; + let _temp_2347 = 0; + let _temp_2348 = 0; + let _temp_2349 = 0; + let _temp_2350 = 0; + let _temp_2351 = 0; + let _temp_2352 = 0; + let _temp_2353 = 0; + let _temp_2354 = 0; + let _temp_2355 = 0; + let _temp_2356 = 0; + let _temp_2357 = 0; + let _temp_2358 = 0; + let _temp_2359 = 0; + let _temp_2360 = 0; + let _temp_2361 = 0; + let _temp_2362 = 0; + let _temp_2363 = 0; + let _temp_2364 = 0; + let _temp_2365 = 0; + let _temp_2366 = 0; + let _temp_2367 = 0; + let _temp_2368 = 0; + let _temp_2369 = 0; + let _temp_2370 = 0; + let _temp_2371 = 0; + let _temp_2372 = 0; + let _temp_2373 = 0; + let _temp_2374 = 0; + let _temp_2375 = 0; + let _temp_2376 = 0; + let _temp_2377 = 0; + let _temp_2378 = 0; + let _temp_2379 = 0; + let _temp_2380 = 0; + let _temp_2381 = 0; + let _temp_2382 = 0; + let _temp_2383 = 0; + let _temp_2384 = 0; + let _temp_2385 = 0; + let _temp_2386 = 0; + let _temp_2387 = 0; + let _temp_2388 = 0; + let _temp_2389 = 0; + let _temp_2390 = 0; + let _temp_2391 = 0; + let _temp_2392 = 0; + let _temp_2393 = 0; + let _temp_2394 = 0; + let _temp_2395 = 0; + let _temp_2396 = 0; + let _temp_2397 = 0; + let _temp_2398 = 0; + let _temp_2399 = 0; + let _temp_2400 = 0; + let _temp_2401 = 0; + let _temp_2402 = 0; + let _temp_2403 = 0; + let _temp_2404 = 0; + let _temp_2405 = 0; + let _temp_2406 = 0; + let _temp_2407 = 0; + let _temp_2408 = 0; + let _temp_2409 = 0; + let _temp_2410 = 0; + let _temp_2411 = 0; + let _temp_2412 = 0; + let _temp_2413 = 0; + let _temp_2414 = 0; + let _temp_2415 = 0; + let _temp_2416 = 0; + let _temp_2417 = 0; + let _temp_2418 = 0; + let _temp_2419 = 0; + let _temp_2420 = 0; + let _temp_2421 = 0; + let _temp_2422 = 0; + let _temp_2423 = 0; + let _temp_2424 = 0; + let _temp_2425 = 0; + let _temp_2426 = 0; + let _temp_2427 = 0; + let _temp_2428 = 0; + let _temp_2429 = 0; + let _temp_2430 = 0; + let _temp_2431 = 0; + let _temp_2432 = 0; + let _temp_2433 = 0; + let _temp_2434 = 0; + let _temp_2435 = 0; + let _temp_2436 = 0; + let _temp_2437 = 0; + let _temp_2438 = 0; + let _temp_2439 = 0; + let _temp_2440 = 0; + let _temp_2441 = 0; + let _temp_2442 = 0; + let _temp_2443 = 0; + let _temp_2444 = 0; + let _temp_2445 = 0; + let _temp_2446 = 0; + let _temp_2447 = 0; + let _temp_2448 = 0; + let _temp_2449 = 0; + let _temp_2450 = 0; + let _temp_2451 = 0; + let _temp_2452 = 0; + let _temp_2453 = 0; + let _temp_2454 = 0; + let _temp_2455 = 0; + let _temp_2456 = 0; + let _temp_2457 = 0; + let _temp_2458 = 0; + let _temp_2459 = 0; + let _temp_2460 = 0; + let _temp_2461 = 0; + let _temp_2462 = 0; + let _temp_2463 = 0; + let _temp_2464 = 0; + let _temp_2465 = 0; + let _temp_2466 = 0; + let _temp_2467 = 0; + let _temp_2468 = 0; + let _temp_2469 = 0; + let _temp_2470 = 0; + let _temp_2471 = 0; + let _temp_2472 = 0; + let _temp_2473 = 0; + let _temp_2474 = 0; + let _temp_2475 = 0; + let _temp_2476 = 0; + let _temp_2477 = 0; + let _temp_2478 = 0; + let _temp_2479 = 0; + let _temp_2480 = 0; + let _temp_2481 = 0; + let _temp_2482 = 0; + let _temp_2483 = 0; + let _temp_2484 = 0; + let _temp_2485 = 0; + let _temp_2486 = 0; + let _temp_2487 = 0; + let _temp_2488 = 0; + let _temp_2489 = 0; + let _temp_2490 = 0; + let _temp_2491 = 0; + let _temp_2492 = 0; + let _temp_2493 = 0; + let _temp_2494 = 0; + let _temp_2495 = 0; + let _temp_2496 = 0; + let _temp_2497 = 0; + let _temp_2498 = 0; + let _temp_2499 = 0; + let _temp_2500 = 0; + let _temp_2501 = 0; + let _temp_2502 = 0; + let _temp_2503 = 0; + let _temp_2504 = 0; + let _temp_2505 = 0; + let _temp_2506 = 0; + let _temp_2507 = 0; + let _temp_2508 = 0; + let _temp_2509 = 0; + let _temp_2510 = 0; + let _temp_2511 = 0; + let _temp_2512 = 0; + let _temp_2513 = 0; + let _temp_2514 = 0; + let _temp_2515 = 0; + let _temp_2516 = 0; + let _temp_2517 = 0; + let _temp_2518 = 0; + let _temp_2519 = 0; + let _temp_2520 = 0; + let _temp_2521 = 0; + let _temp_2522 = 0; + let _temp_2523 = 0; + let _temp_2524 = 0; + let _temp_2525 = 0; + let _temp_2526 = 0; + let _temp_2527 = 0; + let _temp_2528 = 0; + let _temp_2529 = 0; + let _temp_2530 = 0; + let _temp_2531 = 0; + let _temp_2532 = 0; + let _temp_2533 = 0; + let _temp_2534 = 0; + let _temp_2535 = 0; + let _temp_2536 = 0; + let _temp_2537 = 0; + let _temp_2538 = 0; + let _temp_2539 = 0; + let _temp_2540 = 0; + let _temp_2541 = 0; + let _temp_2542 = 0; + let _temp_2543 = 0; + let _temp_2544 = 0; + let _temp_2545 = 0; + let _temp_2546 = 0; + let _temp_2547 = 0; + let _temp_2548 = 0; + let _temp_2549 = 0; + let _temp_2550 = 0; + let _temp_2551 = 0; + let _temp_2552 = 0; + let _temp_2553 = 0; + let _temp_2554 = 0; + let _temp_2555 = 0; + let _temp_2556 = 0; + let _temp_2557 = 0; + let _temp_2558 = 0; + let _temp_2559 = 0; + let _temp_2560 = 0; + let _temp_2561 = 0; + let _temp_2562 = 0; + let _temp_2563 = 0; + let _temp_2564 = 0; + let _temp_2565 = 0; + let _temp_2566 = 0; + let _temp_2567 = 0; + let _temp_2568 = 0; + let _temp_2569 = 0; + let _temp_2570 = 0; + let _temp_2571 = 0; + let _temp_2572 = 0; + let _temp_2573 = 0; + let _temp_2574 = 0; + let _temp_2575 = 0; + let _temp_2576 = 0; + let _temp_2577 = 0; + let _temp_2578 = 0; + let _temp_2579 = 0; + let _temp_2580 = 0; + let _temp_2581 = 0; + let _temp_2582 = 0; + let _temp_2583 = 0; + let _temp_2584 = 0; + let _temp_2585 = 0; + let _temp_2586 = 0; + let _temp_2587 = 0; + let _temp_2588 = 0; + let _temp_2589 = 0; + let _temp_2590 = 0; + let _temp_2591 = 0; + let _temp_2592 = 0; + let _temp_2593 = 0; +} diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index d4d2c8c3d9ccd..1359761457a66 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -2,7 +2,7 @@ error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:23 diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr index a9159562d9d51..acbd0d05984f1 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -9,15 +9,11 @@ LL | let Ok(x) = res; note: `Result<u32, &R>` defined here --> $SRC_DIR/core/src/result.rs:LL:COL | -LL | / pub enum Result<T, E> { -LL | | /// Contains the success value -LL | | #[lang = "Ok"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E), - | | ^^^ not covered -LL | | } - | |_- +LL | pub enum Result<T, E> { + | --------------------- +... +LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E), + | ^^^ not covered = note: the matched value is of type `Result<u32, &R>` help: you might want to use `if let` to ignore the variant that isn't matched | diff --git a/src/test/ui/regions/closure-in-projection-issue-97405.rs b/src/test/ui/regions/closure-in-projection-issue-97405.rs new file mode 100644 index 0000000000000..e567d5c2723f2 --- /dev/null +++ b/src/test/ui/regions/closure-in-projection-issue-97405.rs @@ -0,0 +1,32 @@ +// Regression test for #97405. +// In `good_generic_fn` the param `T` ends up in the substs of closures/generators, +// but we should be able to prove `<Gen<T> as Iterator>::Item: 'static` without +// requiring `T: 'static` + +// edition:2018 +// check-fail + +fn opaque<F>(_: F) -> impl Iterator { b"".iter() } + +fn assert_static<T: 'static>(_: T) {} + +fn good_generic_fn<T>() { + // Previously, proving `<OpaqueTy<type_of(async {})> as Iterator>::Item: 'static` + // used to require `T: 'static`. + assert_static(opaque(async {}).next()); + assert_static(opaque(|| {}).next()); + assert_static(opaque(opaque(async {}).next()).next()); +} + + +// This should fail because `T` ends up in the upvars of the closure. +fn bad_generic_fn<T: Copy>(t: T) { + assert_static(opaque(async move { t; }).next()); + //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough + assert_static(opaque(move || { t; }).next()); + //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough + assert_static(opaque(opaque(async move { t; }).next()).next()); + //~^ ERROR the associated type `<impl Iterator as Iterator>::Item` may not live long enough +} + +fn main() {} diff --git a/src/test/ui/regions/closure-in-projection-issue-97405.stderr b/src/test/ui/regions/closure-in-projection-issue-97405.stderr new file mode 100644 index 0000000000000..c08f1059ebf58 --- /dev/null +++ b/src/test/ui/regions/closure-in-projection-issue-97405.stderr @@ -0,0 +1,30 @@ +error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough + --> $DIR/closure-in-projection-issue-97405.rs:24:5 + | +LL | assert_static(opaque(async move { t; }).next()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... + = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds + +error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough + --> $DIR/closure-in-projection-issue-97405.rs:26:5 + | +LL | assert_static(opaque(move || { t; }).next()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... + = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds + +error[E0310]: the associated type `<impl Iterator as Iterator>::Item` may not live long enough + --> $DIR/closure-in-projection-issue-97405.rs:28:5 + | +LL | assert_static(opaque(opaque(async move { t; }).next()).next()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<impl Iterator as Iterator>::Item: 'static`... + = note: ...so that the type `<impl Iterator as Iterator>::Item` will meet its required lifetime bounds + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs index 9912e88c2ec57..389f82e794be7 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs @@ -23,7 +23,6 @@ where // Here we get an error: we need `'a: 'b`. fn bar<'a, 'b>() //~^ ERROR cannot infer -//~| ERROR cannot infer where <() as Project<'a, 'b>>::Item: Eq, { diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index 2bb58b5ec2df5..5672837290cb1 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -1,35 +1,3 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/regions-normalize-in-where-clause-list.rs:24:1 - | -LL | / fn bar<'a, 'b>() -LL | | -LL | | -LL | | where -LL | | <() as Project<'a, 'b>>::Item: Eq, - | |______________________________________^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined here... - --> $DIR/regions-normalize-in-where-clause-list.rs:24:8 - | -LL | fn bar<'a, 'b>() - | ^^ -note: ...but the lifetime must also be valid for the lifetime `'b` as defined here... - --> $DIR/regions-normalize-in-where-clause-list.rs:24:12 - | -LL | fn bar<'a, 'b>() - | ^^ -note: ...so that the types are compatible - --> $DIR/regions-normalize-in-where-clause-list.rs:24:1 - | -LL | / fn bar<'a, 'b>() -LL | | -LL | | -LL | | where -LL | | <() as Project<'a, 'b>>::Item: Eq, - | |______________________________________^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` - error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:24:4 | @@ -54,6 +22,6 @@ LL | fn bar<'a, 'b>() = note: expected `Project<'a, 'b>` found `Project<'_, '_>` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/repeat-expr/repeat_count.stderr b/src/test/ui/repeat-expr/repeat_count.stderr index 59bcd954a1fde..e222c141f8b6a 100644 --- a/src/test/ui/repeat-expr/repeat_count.stderr +++ b/src/test/ui/repeat-expr/repeat_count.stderr @@ -30,6 +30,12 @@ error[E0308]: mismatched types LL | let e = [0; "foo"]; | ^^^^^ expected `usize`, found `&str` +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:31:17 + | +LL | let g = [0; G { g: () }]; + | ^^^^^^^^^^^ expected `usize`, found struct `G` + error[E0308]: mismatched types --> $DIR/repeat_count.rs:19:17 | @@ -57,12 +63,6 @@ help: change the type of the numeric literal from `u8` to `usize` LL | let f = [0; 4usize]; | ~~~~~ -error[E0308]: mismatched types - --> $DIR/repeat_count.rs:31:17 - | -LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found struct `G` - error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0435. diff --git a/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs new file mode 100644 index 0000000000000..4bf6b54fe0787 --- /dev/null +++ b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] + +pub struct Private { _priv: () } + +#[non_exhaustive] +pub struct NonExhaustive {} + +#[non_exhaustive] +pub enum NonExhaustiveEnum {} + +pub enum NonExhaustiveVariant { + #[non_exhaustive] + A, +} + +pub struct ExternalIndirection<T> { + pub x: T, +} diff --git a/src/test/ui/repr/feature-gate-no-niche.rs b/src/test/ui/repr/feature-gate-no-niche.rs deleted file mode 100644 index 8872ee7119e4a..0000000000000 --- a/src/test/ui/repr/feature-gate-no-niche.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::num::NonZeroU8 as N8; -use std::num::NonZeroU16 as N16; - -#[repr(no_niche)] -pub struct Cloaked(N16); -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(transparent, no_niche)] -pub struct Shadowy(N16); -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(no_niche)] -pub enum Cloaked1 { _A(N16), } -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(no_niche)] -pub enum Cloaked2 { _A(N16), _B(u8, N8) } -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -fn main() { } diff --git a/src/test/ui/repr/feature-gate-no-niche.stderr b/src/test/ui/repr/feature-gate-no-niche.stderr deleted file mode 100644 index 34fd417cc99a2..0000000000000 --- a/src/test/ui/repr/feature-gate-no-niche.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:4:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:8:21 - | -LL | #[repr(transparent, no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:12:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:16:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/repr/issue-83505-repr-simd.stderr b/src/test/ui/repr/issue-83505-repr-simd.stderr index f1390a652016b..df99baaf52293 100644 --- a/src/test/ui/repr/issue-83505-repr-simd.stderr +++ b/src/test/ui/repr/issue-83505-repr-simd.stderr @@ -22,7 +22,7 @@ LL | #[repr(simd)] | ^^^^^^^^^^^^^ ... LL | enum Es {} - | ---------- zero-variant enum + | ------- zero-variant enum error: aborting due to 3 previous errors diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs deleted file mode 100644 index 870eda89c20d7..0000000000000 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(no_niche)] - -use std::num::NonZeroU8 as N8; -use std::num::NonZeroU16 as N16; - -#[repr(no_niche)] -pub union Cloaked1 { _A: N16 } -//~^^ ERROR attribute should be applied to a struct or enum [E0517] - -#[repr(no_niche)] -pub union Cloaked2 { _A: N16, _B: (u8, N8) } -//~^^ ERROR attribute should be applied to a struct or enum [E0517] - -fn main() { } diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr deleted file mode 100644 index 9af929d409473..0000000000000 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0517]: attribute should be applied to a struct or enum - --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ -LL | pub union Cloaked1 { _A: N16 } - | ------------------------------ not a struct or enum - -error[E0517]: attribute should be applied to a struct or enum - --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ -LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) } - | -------------------------------------------- not a struct or enum - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-no-niche.rs b/src/test/ui/repr/repr-no-niche.rs deleted file mode 100644 index 2e6064aeb0074..0000000000000 --- a/src/test/ui/repr/repr-no-niche.rs +++ /dev/null @@ -1,327 +0,0 @@ -// run-pass - -// This file tests repr(no_niche), which causes an struct/enum to hide -// any niche space that may exist in its internal state from the -// context it appears in. - -// Here are the axes this test is seeking to cover: -// -// repr annotation: -// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche) -// -// enum vs struct -// -// niche-type via type-parameter vs inline declaration - -#![feature(decl_macro)] -#![feature(no_niche)] - -use std::mem::size_of; -use std::num::{NonZeroU8, NonZeroU16}; - -mod struct_inline { - use std::num::NonZeroU16 as N16; - - #[derive(Debug)] pub struct Visible(N16); - - #[repr(no_niche)] - #[derive(Debug)] pub struct Cloaked(N16); - - #[repr(transparent)] - #[derive(Debug)] pub struct Transparent(N16); - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub struct Shadowy(N16); -} - -mod struct_param { - #[derive(Debug)] pub struct Visible<T>(T); - - #[repr(no_niche)] - #[derive(Debug)] pub struct Cloaked<T>(T); - - #[repr(transparent)] - #[derive(Debug)] pub struct Transparent<T>(T); - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub struct Shadowy<T>(T); -} - -mod enum_inline { - use crate::two_fifty_six_variant_enum; - use std::num::{NonZeroU8 as N8, NonZeroU16 as N16}; - - #[derive(Debug)] pub enum Visible1 { _A(N16), } - - #[repr(no_niche)] - #[derive(Debug)] pub enum Cloaked1 { _A(N16), } - - // (N.B.: transparent enums must be univariant) - #[repr(transparent)] - #[derive(Debug)] pub enum Transparent { _A(N16), } - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub enum Shadowy { _A(N16), } - - // including multivariant enums for completeness. Payload and - // number of variants (i.e. discriminant size) have been chosen so - // that layout including discriminant is 4 bytes, with no space in - // padding to hide another discrimnant from the surrounding - // context. - // - // (Note that multivariant enums cannot usefully expose a niche in - // general; this test is relying on that.) - two_fifty_six_variant_enum!(Visible2, N8); - - two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8); -} - -mod enum_param { - use super::two_fifty_six_variant_enum; - - #[derive(Debug)] pub enum Visible1<T> { _A(T), } - - #[repr(no_niche)] - #[derive(Debug)] pub enum Cloaked1<T> { _A(T), } - - // (N.B.: transparent enums must be univariant) - #[repr(transparent)] - #[derive(Debug)] pub enum Transparent<T> { _A(T), } - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub enum Shadowy<T> { _A(T), } - - // including multivariant enums for completeness. Same notes apply - // here as above (assuming `T` is instantiated with `NonZeroU8`). - two_fifty_six_variant_enum!(Visible2<T>); - - two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2<T>); -} - -fn main() { - // sanity-checks - assert_eq!(size_of::<struct_inline::Visible>(), 2); - assert_eq!(size_of::<struct_inline::Cloaked>(), 2); - assert_eq!(size_of::<struct_inline::Transparent>(), 2); - assert_eq!(size_of::<struct_inline::Shadowy>(), 2); - - assert_eq!(size_of::<struct_param::Visible<NonZeroU16>>(), 2); - assert_eq!(size_of::<struct_param::Cloaked<NonZeroU16>>(), 2); - assert_eq!(size_of::<struct_param::Transparent<NonZeroU16>>(), 2); - assert_eq!(size_of::<struct_param::Shadowy<NonZeroU16>>(), 2); - - assert_eq!(size_of::<enum_inline::Visible1>(), 2); - assert_eq!(size_of::<enum_inline::Cloaked1>(), 2); - assert_eq!(size_of::<enum_inline::Transparent>(), 2); // transparent enums are univariant - assert_eq!(size_of::<enum_inline::Shadowy>(), 2); - assert_eq!(size_of::<enum_inline::Visible2>(), 4); - assert_eq!(size_of::<enum_inline::Cloaked2>(), 4); - - assert_eq!(size_of::<enum_param::Visible1<NonZeroU16>>(), 2); - assert_eq!(size_of::<enum_param::Cloaked1<NonZeroU16>>(), 2); - assert_eq!(size_of::<enum_param::Transparent<NonZeroU16>>(), 2); - assert_eq!(size_of::<enum_param::Shadowy<NonZeroU16>>(), 2); - assert_eq!(size_of::<enum_param::Visible2<NonZeroU8>>(), 4); - assert_eq!(size_of::<enum_param::Cloaked2<NonZeroU8>>(), 4); - - // now the actual tests of no_niche: how do inputs above compose - // with `Option` type constructor. The cases with a `_+2` are the - // ones where no_niche fires. - assert_eq!(size_of::<Option<struct_inline::Visible>>(), 2); - assert_eq!(size_of::<Option<struct_inline::Cloaked>>(), 2+2); - assert_eq!(size_of::<Option<struct_inline::Transparent>>(), 2); - assert_eq!(size_of::<Option<struct_inline::Shadowy>>(), 2+2); - - assert_eq!(size_of::<Option<struct_param::Visible<NonZeroU16>>>(), 2); - assert_eq!(size_of::<Option<struct_param::Cloaked<NonZeroU16>>>(), 2+2); - assert_eq!(size_of::<Option<struct_param::Transparent<NonZeroU16>>>(), 2); - assert_eq!(size_of::<Option<struct_param::Shadowy<NonZeroU16>>>(), 2+2); - - assert_eq!(size_of::<Option<enum_inline::Visible1>>(), 2); - assert_eq!(size_of::<Option<enum_inline::Cloaked1>>(), 2+2); - assert_eq!(size_of::<Option<enum_inline::Transparent>>(), 2); - assert_eq!(size_of::<Option<enum_inline::Shadowy>>(), 2+2); - // cannot use niche of multivariant payload - assert_eq!(size_of::<Option<enum_inline::Visible2>>(), 4+2); - assert_eq!(size_of::<Option<enum_inline::Cloaked2>>(), 4+2); - - assert_eq!(size_of::<Option<enum_param::Visible1<NonZeroU16>>>(), 2); - assert_eq!(size_of::<Option<enum_param::Cloaked1<NonZeroU16>>>(), 2+2); - assert_eq!(size_of::<Option<enum_param::Transparent<NonZeroU16>>>(), 2); - assert_eq!(size_of::<Option<enum_param::Shadowy<NonZeroU16>>>(), 2+2); - // cannot use niche of multivariant payload - assert_eq!(size_of::<Option<enum_param::Visible2<NonZeroU8>>>(), 4+2); - assert_eq!(size_of::<Option<enum_param::Cloaked2<NonZeroU8>>>(), 4+2); -} - -macro two_fifty_six_variant_enum { - ($(#[$attr:meta])* $name:ident<$param:ident>) => { - #[derive(Debug)] $(#[$attr])* - pub enum $name<$param> { - _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), - _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), - _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), - _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), - - _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), - _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), - _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), - _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), - - _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), - _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), - _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), - _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), - - _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), - _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), - _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), - _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), - - _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), - _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), - _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), - _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), - - _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), - _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), - _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), - _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), - - _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), - _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), - _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), - _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), - - _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), - _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), - _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), - _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), - - _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), - _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), - _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), - _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), - - _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), - _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), - _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), - _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), - - _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), - _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), - _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), - _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), - - _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), - _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), - _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), - _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), - - _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), - _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), - _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), - _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), - - _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), - _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), - _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), - _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), - - _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), - _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), - _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), - _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), - - _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), - _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), - _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), - _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), - } - }, - - ($(#[$attr:meta])* $name:ident, $param:ty) => { - #[derive(Debug)] $(#[$attr])* - pub enum $name { - _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), - _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), - _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), - _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), - - _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), - _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), - _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), - _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), - - _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), - _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), - _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), - _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), - - _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), - _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), - _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), - _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), - - _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), - _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), - _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), - _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), - - _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), - _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), - _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), - _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), - - _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), - _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), - _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), - _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), - - _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), - _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), - _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), - _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), - - _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), - _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), - _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), - _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), - - _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), - _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), - _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), - _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), - - _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), - _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), - _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), - _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), - - _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), - _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), - _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), - _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), - - _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), - _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), - _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), - _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), - - _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), - _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), - _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), - _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), - - _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), - _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), - _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), - _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), - - _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), - _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), - _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), - _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), - } - } -} diff --git a/src/test/ui/repr/repr-packed-contains-align.rs b/src/test/ui/repr/repr-packed-contains-align.rs index 67d87eb5cd520..bef5c7d8c62fc 100644 --- a/src/test/ui/repr/repr-packed-contains-align.rs +++ b/src/test/ui/repr/repr-packed-contains-align.rs @@ -1,16 +1,19 @@ -#![feature(untagged_unions)] #![allow(dead_code)] #[repr(align(16))] +#[derive(Clone, Copy)] struct SA(i32); +#[derive(Clone, Copy)] struct SB(SA); #[repr(align(16))] +#[derive(Clone, Copy)] union UA { i: i32 } +#[derive(Clone, Copy)] union UB { a: UA } diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr index 32f9bb8bf33d9..4c3a960cad2a6 100644 --- a/src/test/ui/repr/repr-packed-contains-align.stderr +++ b/src/test/ui/repr/repr-packed-contains-align.stderr @@ -1,151 +1,135 @@ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:19:1 + --> $DIR/repr-packed-contains-align.rs:22:1 | LL | struct SC(SA); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ | note: `SA` has a `#[repr(align)]` attribute --> $DIR/repr-packed-contains-align.rs:5:1 | LL | struct SA(i32); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:22:1 + --> $DIR/repr-packed-contains-align.rs:25:1 | LL | struct SD(SB); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ | note: `SA` has a `#[repr(align)]` attribute --> $DIR/repr-packed-contains-align.rs:5:1 | LL | struct SA(i32); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^ note: `SD` contains a field of type `SB` - --> $DIR/repr-packed-contains-align.rs:22:11 + --> $DIR/repr-packed-contains-align.rs:25:11 | LL | struct SD(SB); | ^^ note: ...which contains a field of type `SA` - --> $DIR/repr-packed-contains-align.rs:7:11 + --> $DIR/repr-packed-contains-align.rs:8:11 | LL | struct SB(SA); | ^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:25:1 + --> $DIR/repr-packed-contains-align.rs:28:1 | LL | struct SE(UA); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | -LL | / union UA { -LL | | i: i32 -LL | | } - | |_^ +LL | union UA { + | ^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:28:1 + --> $DIR/repr-packed-contains-align.rs:31:1 | LL | struct SF(UB); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | -LL | / union UA { -LL | | i: i32 -LL | | } - | |_^ +LL | union UA { + | ^^^^^^^^ note: `SF` contains a field of type `UB` - --> $DIR/repr-packed-contains-align.rs:28:11 + --> $DIR/repr-packed-contains-align.rs:31:11 | LL | struct SF(UB); | ^^ note: ...which contains a field of type `UA` - --> $DIR/repr-packed-contains-align.rs:15:5 + --> $DIR/repr-packed-contains-align.rs:18:5 | LL | a: UA | ^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:31:1 + --> $DIR/repr-packed-contains-align.rs:34:1 | -LL | / union UC { -LL | | a: UA -LL | | } - | |_^ +LL | union UC { + | ^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | -LL | / union UA { -LL | | i: i32 -LL | | } - | |_^ +LL | union UA { + | ^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:36:1 + --> $DIR/repr-packed-contains-align.rs:39:1 | -LL | / union UD { -LL | | n: UB -LL | | } - | |_^ +LL | union UD { + | ^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | -LL | / union UA { -LL | | i: i32 -LL | | } - | |_^ +LL | union UA { + | ^^^^^^^^ note: `UD` contains a field of type `UB` - --> $DIR/repr-packed-contains-align.rs:37:5 + --> $DIR/repr-packed-contains-align.rs:40:5 | LL | n: UB | ^ note: ...which contains a field of type `UA` - --> $DIR/repr-packed-contains-align.rs:15:5 + --> $DIR/repr-packed-contains-align.rs:18:5 | LL | a: UA | ^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:41:1 + --> $DIR/repr-packed-contains-align.rs:44:1 | -LL | / union UE { -LL | | a: SA -LL | | } - | |_^ +LL | union UE { + | ^^^^^^^^ | note: `SA` has a `#[repr(align)]` attribute --> $DIR/repr-packed-contains-align.rs:5:1 | LL | struct SA(i32); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:46:1 + --> $DIR/repr-packed-contains-align.rs:49:1 | -LL | / union UF { -LL | | n: SB -LL | | } - | |_^ +LL | union UF { + | ^^^^^^^^ | note: `SA` has a `#[repr(align)]` attribute --> $DIR/repr-packed-contains-align.rs:5:1 | LL | struct SA(i32); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^ note: `UF` contains a field of type `SB` - --> $DIR/repr-packed-contains-align.rs:47:5 + --> $DIR/repr-packed-contains-align.rs:50:5 | LL | n: SB | ^ note: ...which contains a field of type `SA` - --> $DIR/repr-packed-contains-align.rs:7:11 + --> $DIR/repr-packed-contains-align.rs:8:11 | LL | struct SB(SA); | ^^ diff --git a/src/test/ui/repr/repr-transparent-issue-87496.stderr b/src/test/ui/repr/repr-transparent-issue-87496.stderr index c488755cc242c..3dc13b1c13c97 100644 --- a/src/test/ui/repr/repr-transparent-issue-87496.stderr +++ b/src/test/ui/repr/repr-transparent-issue-87496.stderr @@ -10,7 +10,7 @@ note: the type is defined here --> $DIR/repr-transparent-issue-87496.rs:6:1 | LL | struct TransparentCustomZst(()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/repr-transparent-non-exhaustive.rs new file mode 100644 index 0000000000000..9ccd8610dad47 --- /dev/null +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.rs @@ -0,0 +1,96 @@ +#![deny(repr_transparent_external_private_fields)] + +// aux-build: repr-transparent-non-exhaustive.rs +extern crate repr_transparent_non_exhaustive; + +use repr_transparent_non_exhaustive::{ + Private, + NonExhaustive, + NonExhaustiveEnum, + NonExhaustiveVariant, + ExternalIndirection, +}; + +pub struct InternalPrivate { + _priv: (), +} + +#[non_exhaustive] +pub struct InternalNonExhaustive; + +pub struct InternalIndirection<T> { + x: T, +} + +pub type Sized = i32; + +#[repr(transparent)] +pub struct T1(Sized, InternalPrivate); +#[repr(transparent)] +pub struct T2(Sized, InternalNonExhaustive); +#[repr(transparent)] +pub struct T3(Sized, InternalIndirection<(InternalPrivate, InternalNonExhaustive)>); +#[repr(transparent)] +pub struct T4(Sized, ExternalIndirection<(InternalPrivate, InternalNonExhaustive)>); + +#[repr(transparent)] +pub struct T5(Sized, Private); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T6(Sized, NonExhaustive); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T7(Sized, NonExhaustiveEnum); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T8(Sized, NonExhaustiveVariant); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T9(Sized, InternalIndirection<Private>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T10(Sized, InternalIndirection<NonExhaustive>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T13(Sized, ExternalIndirection<Private>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T14(Sized, ExternalIndirection<NonExhaustive>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.stderr b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr new file mode 100644 index 0000000000000..3b1e334a0cbe2 --- /dev/null +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr @@ -0,0 +1,127 @@ +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:37:22 + | +LL | pub struct T5(Sized, Private); + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/repr-transparent-non-exhaustive.rs:1:9 + | +LL | #![deny(repr_transparent_external_private_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:42:22 + | +LL | pub struct T6(Sized, NonExhaustive); + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:47:22 + | +LL | pub struct T7(Sized, NonExhaustiveEnum); + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:52:22 + | +LL | pub struct T8(Sized, NonExhaustiveVariant); + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:57:22 + | +LL | pub struct T9(Sized, InternalIndirection<Private>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:62:23 + | +LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:67:23 + | +LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:72:23 + | +LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:77:23 + | +LL | pub struct T13(Sized, ExternalIndirection<Private>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:82:23 + | +LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:87:23 + | +LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:92:23 + | +LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586> + = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr index 001a181881f14..f1c570b952356 100644 --- a/src/test/ui/repr/repr-transparent.stderr +++ b/src/test/ui/repr/repr-transparent.stderr @@ -2,9 +2,8 @@ error[E0690]: transparent struct needs at most one non-zero-sized field, but has --> $DIR/repr-transparent.rs:26:1 | LL | struct MultipleNonZst(u8, u8); - | ^^^^^^^^^^^^^^^^^^^^^^--^^--^^ - | | | | - | | | this field is non-zero-sized + | ^^^^^^^^^^^^^^^^^^^^^ -- -- this field is non-zero-sized + | | | | | this field is non-zero-sized | needs at most one non-zero-sized field, but has 2 @@ -12,9 +11,8 @@ error[E0690]: transparent struct needs at most one non-zero-sized field, but has --> $DIR/repr-transparent.rs:32:1 | LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^ - | | | | - | | | this field is non-zero-sized + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- ------------------- this field is non-zero-sized + | | | | | this field is non-zero-sized | needs at most one non-zero-sized field, but has 2 @@ -36,7 +34,7 @@ error[E0084]: unsupported representation for zero-variant enum LL | #[repr(transparent)] | ^^^^^^^^^^^^^^^^^^^^ LL | enum Void {} - | ------------ zero-variant enum + | --------- zero-variant enum error[E0731]: transparent enum needs exactly one variant, but has 0 --> $DIR/repr-transparent.rs:45:1 @@ -60,7 +58,7 @@ error[E0731]: transparent enum needs exactly one variant, but has 2 LL | enum MultipleVariants { | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2 LL | Foo(String), - | ----------- + | --- LL | Bar, | --- too many variants in `MultipleVariants` diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 0dcf0184db107..f839bd4243229 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:24>` +error[E0391]: cycle detected when computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:21>` --> $DIR/issue-23305.rs:5:16 | LL | impl dyn ToNbt<Self> {} | ^^^^ | - = note: ...which immediately requires computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:24>` again + = note: ...which immediately requires computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:21>` again note: cycle used when collecting item types in top-level module --> $DIR/issue-23305.rs:1:1 | diff --git a/src/test/ui/resolve/issue-55673.rs b/src/test/ui/resolve/issue-55673.rs new file mode 100644 index 0000000000000..0436bd397424c --- /dev/null +++ b/src/test/ui/resolve/issue-55673.rs @@ -0,0 +1,12 @@ +trait Foo { + type Bar; +} + +fn foo<T: Foo>() +where + T::Baa: std::fmt::Debug, + //~^ ERROR associated type `Baa` not found for `T` +{ +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-55673.stderr b/src/test/ui/resolve/issue-55673.stderr new file mode 100644 index 0000000000000..39318f959056f --- /dev/null +++ b/src/test/ui/resolve/issue-55673.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Baa` not found for `T` + --> $DIR/issue-55673.rs:7:8 + | +LL | T::Baa: std::fmt::Debug, + | ^^^ there is a similarly named associated type `Bar` in the trait `Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 81d8a34881c0c..e546d9f64ecad 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -318,7 +318,7 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:27:20 | LL | Fn(u8), - | ------ fn(u8) -> Z {Z::Fn} defined here + | -- fn(u8) -> Z {Z::Fn} defined here ... LL | let _: Z = Z::Fn; | - ^^^^^ expected enum `Z`, found fn item @@ -353,7 +353,7 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:43:16 | LL | Fn(u8), - | ------ fn(u8) -> E {E::Fn} defined here + | -- fn(u8) -> E {E::Fn} defined here ... LL | let _: E = m::E::Fn; | - ^^^^^^^^ expected enum `E`, found fn item @@ -388,7 +388,7 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:51:16 | LL | Fn(u8), - | ------ fn(u8) -> E {E::Fn} defined here + | -- fn(u8) -> E {E::Fn} defined here ... LL | let _: E = E::Fn; | - ^^^^^ expected enum `E`, found fn item diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index ada053014ef5e..17a666a401ce8 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -114,7 +114,7 @@ note: the tuple struct constructor `S` is defined here --> $DIR/auxiliary/privacy-struct-ctor.rs:2:5 | LL | pub struct S(u8); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:45:19 @@ -131,7 +131,7 @@ note: the tuple struct constructor `Z` is defined here --> $DIR/auxiliary/privacy-struct-ctor.rs:5:9 | LL | pub(in m) struct Z(pub(in m::n) u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 10 previous errors diff --git a/src/test/ui/resolve/resolve-self-in-impl.stderr b/src/test/ui/resolve/resolve-self-in-impl.stderr index 7f623e47353b9..aa99c1a33352e 100644 --- a/src/test/ui/resolve/resolve-self-in-impl.stderr +++ b/src/test/ui/resolve/resolve-self-in-impl.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:20>` +error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:17>` --> $DIR/resolve-self-in-impl.rs:14:13 | LL | impl Tr for Self {} | ^^^^ | - = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:20>` again + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:17>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -17,13 +17,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:23>` +error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:20>` --> $DIR/resolve-self-in-impl.rs:15:15 | LL | impl Tr for S<Self> {} | ^^^^ | - = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:23>` again + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:20>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -36,13 +36,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:13>` +error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:10>` --> $DIR/resolve-self-in-impl.rs:16:6 | LL | impl Self {} | ^^^^ | - = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:13>` again + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:10>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -55,13 +55,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:16>` +error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:13>` --> $DIR/resolve-self-in-impl.rs:17:8 | LL | impl S<Self> {} | ^^^^ | - = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:16>` again + = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:13>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -74,13 +74,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:26>` +error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:23>` --> $DIR/resolve-self-in-impl.rs:18:1 | LL | impl Tr<Self::A> for S {} | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:26>` again + = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:23>` again note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | diff --git a/src/test/ui/rfc-2005-default-binding-mode/const.stderr b/src/test/ui/rfc-2005-default-binding-mode/const.stderr index 10d30ec1a1b18..0f567125432b2 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/const.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/const.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/const.rs:14:9 | LL | const FOO: Foo = Foo{bar: 5}; - | ----------------------------- constant defined here + | -------------- constant defined here ... LL | match &f { | -- this expression has type `&Foo` diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr index 5ef078c20057d..872cb9b8bc68e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr @@ -8,7 +8,7 @@ note: `EmptyNonExhaustiveEnum` defined here --> $DIR/auxiliary/enums.rs:18:1 | LL | pub enum EmptyNonExhaustiveEnum {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -26,12 +26,8 @@ LL | match enum_unit { note: `NonExhaustiveEnum` defined here --> $DIR/auxiliary/enums.rs:4:1 | -LL | / pub enum NonExhaustiveEnum { -LL | | Unit, -LL | | Tuple(u32), -LL | | Struct { field: u32 }, -LL | | } - | |_^ +LL | pub enum NonExhaustiveEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -48,12 +44,8 @@ LL | match enum_unit {}; note: `NonExhaustiveEnum` defined here --> $DIR/auxiliary/enums.rs:4:1 | -LL | / pub enum NonExhaustiveEnum { -LL | | Unit, -LL | | Tuple(u32), -LL | | Struct { field: u32 }, -LL | | } - | |_^ +LL | pub enum NonExhaustiveEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs index 3c4a09fafd2db..143f9a3009b61 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.rs @@ -3,11 +3,11 @@ struct Foo; #[non_exhaustive] -//~^ ERROR attribute can only be applied to a struct or enum [E0701] +//~^ ERROR attribute should be applied to a struct or enum [E0701] trait Bar { } #[non_exhaustive] -//~^ ERROR attribute can only be applied to a struct or enum [E0701] +//~^ ERROR attribute should be applied to a struct or enum [E0701] union Baz { f1: u16, f2: u16 diff --git a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr index 76d9e2d8205b7..136cd763b05c1 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -4,7 +4,7 @@ error: malformed `non_exhaustive` attribute input LL | #[non_exhaustive(anything)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]` -error[E0701]: attribute can only be applied to a struct or enum +error[E0701]: attribute should be applied to a struct or enum --> $DIR/invalid-attribute.rs:5:1 | LL | #[non_exhaustive] @@ -13,7 +13,7 @@ LL | LL | trait Bar { } | ------------- not a struct or enum -error[E0701]: attribute can only be applied to a struct or enum +error[E0701]: attribute should be applied to a struct or enum --> $DIR/invalid-attribute.rs:9:1 | LL | #[non_exhaustive] diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr index 272b2ef6ee1d1..2b34d0711793f 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -25,7 +25,7 @@ note: the tuple struct constructor `TupleStruct` is defined here --> $DIR/auxiliary/structs.rs:12:1 | LL | pub struct TupleStruct(pub u16, pub u16); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0603]: unit struct `UnitStruct` is private --> $DIR/struct.rs:32:32 @@ -37,7 +37,7 @@ note: the unit struct `UnitStruct` is defined here --> $DIR/auxiliary/structs.rs:9:1 | LL | pub struct UnitStruct; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error[E0639]: cannot create non-exhaustive struct using struct expression --> $DIR/struct.rs:7:14 diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr index 2dc4eabb8630a..66e93291c72a0 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -8,7 +8,7 @@ note: `IndirectUninhabitedEnum` defined here --> $DIR/auxiliary/uninhabited.rs:26:1 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -27,7 +27,7 @@ note: `IndirectUninhabitedStruct` defined here --> $DIR/auxiliary/uninhabited.rs:28:1 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -46,7 +46,7 @@ note: `IndirectUninhabitedTupleStruct` defined here --> $DIR/auxiliary/uninhabited.rs:30:1 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedTupleStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -65,7 +65,7 @@ note: `IndirectUninhabitedVariants` defined here --> $DIR/auxiliary/uninhabited.rs:32:1 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr index f0cb13de3f799..ef97c1fa17f39 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -8,7 +8,7 @@ note: `IndirectUninhabitedEnum` defined here --> $DIR/auxiliary/uninhabited.rs:26:1 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -27,7 +27,7 @@ note: `IndirectUninhabitedStruct` defined here --> $DIR/auxiliary/uninhabited.rs:28:1 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -46,7 +46,7 @@ note: `IndirectUninhabitedTupleStruct` defined here --> $DIR/auxiliary/uninhabited.rs:30:1 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedTupleStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -65,7 +65,7 @@ note: `IndirectUninhabitedVariants` defined here --> $DIR/auxiliary/uninhabited.rs:32:1 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `IndirectUninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr index 49febd9241dc6..32a5c07f19688 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -7,9 +7,8 @@ LL | match x {} note: `UninhabitedEnum` defined here --> $DIR/auxiliary/uninhabited.rs:5:1 | -LL | / pub enum UninhabitedEnum { -LL | | } - | |_^ +LL | pub enum UninhabitedEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -27,10 +26,8 @@ LL | match x {} note: `UninhabitedStruct` defined here --> $DIR/auxiliary/uninhabited.rs:9:1 | -LL | / pub struct UninhabitedStruct { -LL | | _priv: !, -LL | | } - | |_^ +LL | pub struct UninhabitedStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UninhabitedStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -49,7 +46,7 @@ note: `UninhabitedTupleStruct` defined here --> $DIR/auxiliary/uninhabited.rs:14:1 | LL | pub struct UninhabitedTupleStruct(!); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UninhabitedTupleStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -67,13 +64,12 @@ LL | match x {} note: `UninhabitedVariants` defined here --> $DIR/auxiliary/uninhabited.rs:17:23 | -LL | / pub enum UninhabitedVariants { -LL | | #[non_exhaustive] Tuple(!), - | | ^^^^^ not covered -LL | | #[non_exhaustive] Struct { x: ! } - | | ^^^^^^ not covered -LL | | } - | |_- +LL | pub enum UninhabitedVariants { + | ---------------------------- +LL | #[non_exhaustive] Tuple(!), + | ^^^^^ not covered +LL | #[non_exhaustive] Struct { x: ! } + | ^^^^^^ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index e18c2678d323c..d854ea28ff68d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -7,9 +7,8 @@ LL | match x {} note: `UninhabitedEnum` defined here --> $DIR/auxiliary/uninhabited.rs:5:1 | -LL | / pub enum UninhabitedEnum { -LL | | } - | |_^ +LL | pub enum UninhabitedEnum { + | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -27,10 +26,8 @@ LL | match x {} note: `UninhabitedStruct` defined here --> $DIR/auxiliary/uninhabited.rs:9:1 | -LL | / pub struct UninhabitedStruct { -LL | | _priv: !, -LL | | } - | |_^ +LL | pub struct UninhabitedStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UninhabitedStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -49,7 +46,7 @@ note: `UninhabitedTupleStruct` defined here --> $DIR/auxiliary/uninhabited.rs:14:1 | LL | pub struct UninhabitedTupleStruct(!); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: the matched value is of type `UninhabitedTupleStruct` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown | @@ -67,13 +64,12 @@ LL | match x {} note: `UninhabitedVariants` defined here --> $DIR/auxiliary/uninhabited.rs:17:23 | -LL | / pub enum UninhabitedVariants { -LL | | #[non_exhaustive] Tuple(!), - | | ^^^^^ not covered -LL | | #[non_exhaustive] Struct { x: ! } - | | ^^^^^^ not covered -LL | | } - | |_- +LL | pub enum UninhabitedVariants { + | ---------------------------- +LL | #[non_exhaustive] Tuple(!), + | ^^^^^ not covered +LL | #[non_exhaustive] Struct { x: ! } + | ^^^^^^ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr index 64cae3748c91e..720b7b119cec9 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr @@ -8,7 +8,7 @@ note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | LL | #[non_exhaustive] Tuple(u32), - | ^^^^^^^^^^ + | ^^^^^ error[E0603]: unit variant `Unit` is private --> $DIR/variant.rs:14:47 @@ -44,7 +44,7 @@ note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | LL | #[non_exhaustive] Tuple(u32), - | ^^^^^^^^^^ + | ^^^^^ error[E0603]: tuple variant `Tuple` is private --> $DIR/variant.rs:26:35 @@ -56,7 +56,7 @@ note: the tuple variant `Tuple` is defined here --> $DIR/auxiliary/variants.rs:5:23 | LL | #[non_exhaustive] Tuple(u32), - | ^^^^^^^^^^ + | ^^^^^ error[E0639]: cannot create non-exhaustive variant using struct expression --> $DIR/variant.rs:8:26 diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs index bc0ca9552806f..2d2b01b6f947a 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs @@ -1,5 +1,5 @@ #[track_caller] struct S; -//~^^ ERROR attribute should be applied to function +//~^^ ERROR attribute should be applied to a function definition fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr index 6666dcfa6e599..b36597bded941 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr @@ -1,10 +1,10 @@ -error[E0739]: attribute should be applied to function +error[E0739]: attribute should be applied to a function definition --> $DIR/only-for-fns.rs:1:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | struct S; - | --------- not a function + | --------- not a function definition error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr index 1da8e648251ad..76300cce55cd4 100644 --- a/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/cross-crate.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/cross-crate.rs:4:1 | -LL | / struct Foo<'a, T> { -LL | | bar: std::slice::IterMut<'a, T> -LL | | } - | |_^ +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ | = note: T: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.stderr b/src/test/ui/rfc-2093-infer-outlives/enum.stderr index 868ca2c4587d1..b6ce2450e22aa 100644 --- a/src/test/ui/rfc-2093-infer-outlives/enum.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/enum.stderr @@ -1,30 +1,24 @@ error: rustc_outlives --> $DIR/enum.rs:7:1 | -LL | / enum Foo<'a, T> { -LL | | One(Bar<'a, T>) -LL | | } - | |_^ +LL | enum Foo<'a, T> { + | ^^^^^^^^^^^^^^^ | = note: T: 'a error: rustc_outlives --> $DIR/enum.rs:13:1 | -LL | / struct Bar<'b, U> { -LL | | field2: &'b U -LL | | } - | |_^ +LL | struct Bar<'b, U> { + | ^^^^^^^^^^^^^^^^^ | = note: U: 'b error: rustc_outlives --> $DIR/enum.rs:19:1 | -LL | / enum Ying<'c, K> { -LL | | One(&'c Yang<K>) -LL | | } - | |_^ +LL | enum Ying<'c, K> { + | ^^^^^^^^^^^^^^^^ | = note: K: 'c diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr index 4608962c7c3f8..595a5c28088d6 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr @@ -1,11 +1,8 @@ error: rustc_outlives --> $DIR/explicit-dyn.rs:7:1 | -LL | / struct Foo<'a, A> -LL | | { -LL | | foo: Box<dyn Trait<'a, A>> -LL | | } - | |_^ +LL | struct Foo<'a, A> + | ^^^^^^^^^^^^^^^^^ | = note: A: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr index 062f5d5e9a73d..3059f95aefbd1 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/explicit-enum.rs:4:1 | -LL | / enum Foo<'a, U> { -LL | | One(Bar<'a, U>) -LL | | } - | |_^ +LL | enum Foo<'a, U> { + | ^^^^^^^^^^^^^^^ | = note: U: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr index a85aa3d7565ba..589e95899132d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr @@ -1,11 +1,8 @@ error: rustc_outlives --> $DIR/explicit-projection.rs:8:1 | -LL | / struct Foo<'a, A, B> where A: Trait<'a, B> -LL | | { -LL | | foo: <A as Trait<'a, B>>::Type -LL | | } - | |_^ +LL | struct Foo<'a, A, B> where A: Trait<'a, B> + | ^^^^^^^^^^^^^^^^^^^^ | = note: B: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr index 309c54bb44934..9912e36b29c1a 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/explicit-struct.rs:4:1 | -LL | / struct Foo<'b, U> { -LL | | bar: Bar<'b, U> -LL | | } - | |_^ +LL | struct Foo<'b, U> { + | ^^^^^^^^^^^^^^^^^ | = note: U: 'b diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs index ea8a3c177e9d7..871208b5ba785 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs @@ -1,11 +1,11 @@ #![feature(rustc_attrs)] -#![feature(untagged_unions)] #[rustc_outlives] union Foo<'b, U: Copy> { //~ ERROR rustc_outlives bar: Bar<'b, U> } +#[derive(Clone, Copy)] union Bar<'a, T: Copy> where T: 'a { x: &'a (), y: T, diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr index 47c283faf5073..16b64bdc29dd3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr @@ -1,10 +1,8 @@ error: rustc_outlives - --> $DIR/explicit-union.rs:5:1 + --> $DIR/explicit-union.rs:4:1 | -LL | / union Foo<'b, U: Copy> { -LL | | bar: Bar<'b, U> -LL | | } - | |_^ +LL | union Foo<'b, U: Copy> { + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: U: 'b diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr index 10387f51b1e44..4350e6e8beec2 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr @@ -1,11 +1,8 @@ error: rustc_outlives --> $DIR/nested-enum.rs:4:1 | -LL | / enum Foo<'a, T> { -LL | | -LL | | One(Bar<'a, T>) -LL | | } - | |_^ +LL | enum Foo<'a, T> { + | ^^^^^^^^^^^^^^^ | = note: T: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr index ffdd5542bb4b5..c08add7ededec 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/nested-regions.rs:4:1 | -LL | / struct Foo<'a, 'b, T> { -LL | | x: &'a &'b T -LL | | } - | |_^ +LL | struct Foo<'a, 'b, T> { + | ^^^^^^^^^^^^^^^^^^^^^ | = note: 'b: 'a = note: T: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr index 86bcbe640e4bc..7695552344370 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/nested-structs.rs:4:1 | -LL | / struct Foo<'a, T> { -LL | | field1: Bar<'a, T> -LL | | } - | |_^ +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ | = note: T: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs index 0da3cc2ba1b04..27ebd0b54db5d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs @@ -1,5 +1,4 @@ #![feature(rustc_attrs)] -#![feature(untagged_unions)] #[rustc_outlives] union Foo<'a, T: Copy> { //~ ERROR rustc_outlives @@ -7,6 +6,7 @@ union Foo<'a, T: Copy> { //~ ERROR rustc_outlives } // Type U needs to outlive lifetime 'b +#[derive(Clone, Copy)] union Bar<'b, U: Copy> { field2: &'b U } diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr index e0f248fa38a04..a785c63ce3d99 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr @@ -1,10 +1,8 @@ error: rustc_outlives - --> $DIR/nested-union.rs:5:1 + --> $DIR/nested-union.rs:4:1 | -LL | / union Foo<'a, T: Copy> { -LL | | field1: Bar<'a, T> -LL | | } - | |_^ +LL | union Foo<'a, T: Copy> { + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: T: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.stderr b/src/test/ui/rfc-2093-infer-outlives/projection.stderr index 840676e796671..d9342013f554f 100644 --- a/src/test/ui/rfc-2093-infer-outlives/projection.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/projection.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/projection.rs:4:1 | -LL | / struct Foo<'a, T: Iterator> { -LL | | bar: &'a T::Item -LL | | } - | |_^ +LL | struct Foo<'a, T: Iterator> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: <T as Iterator>::Item: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr index d69aaf6f849fa..5081143578177 100644 --- a/src/test/ui/rfc-2093-infer-outlives/reference.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/reference.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/reference.rs:4:1 | -LL | / struct Foo<'a, T> { -LL | | bar: &'a T, -LL | | } - | |_^ +LL | struct Foo<'a, T> { + | ^^^^^^^^^^^^^^^^^ | = note: T: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr index 7836b3f5aabed..9c836b190cff9 100644 --- a/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr @@ -1,11 +1,8 @@ error: rustc_outlives --> $DIR/self-dyn.rs:8:1 | -LL | / struct Foo<'a, 'b, A> -LL | | { -LL | | foo: Box<dyn Trait<'a, 'b, A>> -LL | | } - | |_^ +LL | struct Foo<'a, 'b, A> + | ^^^^^^^^^^^^^^^^^^^^^ | = note: A: 'a diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr index b972ad8446602..2b4625f77a5e3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr @@ -1,10 +1,8 @@ error: rustc_outlives --> $DIR/self-structs.rs:4:1 | -LL | / struct Foo<'a, 'b, T> { -LL | | field1: dyn Bar<'a, 'b, T> -LL | | } - | |_^ +LL | struct Foo<'a, 'b, T> { + | ^^^^^^^^^^^^^^^^^^^^^ | = note: T: 'a diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index 4a36515b99128..689fdcebbfba4 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -8,40 +8,33 @@ fn _if_let_guard() { //~^ ERROR `if let` guards are experimental () if (let 0 = 1) => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement () if (((let 0 = 1))) => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement () if true && let 0 = 1 => {} //~^ ERROR `if let` guards are experimental - //~| ERROR `let` expressions in this position are unstable () if let 0 = 1 && true => {} //~^ ERROR `if let` guards are experimental - //~| ERROR `let` expressions in this position are unstable () if (let 0 = 1) && true => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement () if true && (let 0 = 1) => {} - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement () if (let 0 = 1) && (let 0 = 1) => {} - //~^ ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} //~^ ERROR `if let` guards are experimental - //~| ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable - //~| ERROR `let` expressions in this position are unstable + //~| ERROR expected expression, found `let` statement () if let Range { start: _, end: _ } = (true..true) && false => {} //~^ ERROR `if let` guards are experimental - //~| ERROR `let` expressions in this position are unstable _ => {} } @@ -57,9 +50,9 @@ fn _macros() { } } use_expr!((let 0 = 1 && 0 == 0)); - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); - //~^ ERROR `let` expressions in this position are unstable + //~^ ERROR expected expression, found `let` statement match () { #[cfg(FALSE)] () if let 0 = 1 => {} diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index 8d93fb87f7ad1..b61041050a8a1 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -1,5 +1,59 @@ +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:10:16 + | +LL | () if (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:13:18 + | +LL | () if (((let 0 = 1))) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:22:16 + | +LL | () if (let 0 = 1) && true => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:25:24 + | +LL | () if true && (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:28:16 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:28:31 + | +LL | () if (let 0 = 1) && (let 0 = 1) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:32:42 + | +LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:52:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/feature-gate.rs:54:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + error: no rules expected the token `let` - --> $DIR/feature-gate.rs:69:15 + --> $DIR/feature-gate.rs:62:15 | LL | macro_rules! use_expr { | --------------------- when calling this macro @@ -28,7 +82,7 @@ LL | () if true && let 0 = 1 => {} = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:20:12 + --> $DIR/feature-gate.rs:19:12 | LL | () if let 0 = 1 && true => {} | ^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +92,7 @@ LL | () if let 0 = 1 && true => {} = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:34:12 + --> $DIR/feature-gate.rs:32:12 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +102,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:42:12 + --> $DIR/feature-gate.rs:36:12 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +112,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` error[E0658]: `if let` guards are experimental - --> $DIR/feature-gate.rs:65:12 + --> $DIR/feature-gate.rs:58:12 | LL | () if let 0 = 1 => {} | ^^^^^^^^^^^^ @@ -67,150 +121,6 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:10:16 - | -LL | () if (let 0 = 1) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:13:18 - | -LL | () if (((let 0 = 1))) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:16:23 - | -LL | () if true && let 0 = 1 => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:20:15 - | -LL | () if let 0 = 1 && true => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:24:16 - | -LL | () if (let 0 = 1) && true => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:27:24 - | -LL | () if true && (let 0 = 1) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:30:16 - | -LL | () if (let 0 = 1) && (let 0 = 1) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:30:31 - | -LL | () if (let 0 = 1) && (let 0 = 1) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:34:15 - | -LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:34:28 - | -LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:34:42 - | -LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:34:55 - | -LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:34:68 - | -LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:42:15 - | -LL | () if let Range { start: _, end: _ } = (true..true) && false => {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:59:16 - | -LL | use_expr!((let 0 = 1 && 0 == 0)); - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:61:16 - | -LL | use_expr!((let 0 = 1)); - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error: aborting due to 23 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2497-if-let-chains/allowed-syntax.rs b/src/test/ui/rfc-2497-if-let-chains/allowed-syntax.rs new file mode 100644 index 0000000000000..ffe0499fda23a --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/allowed-syntax.rs @@ -0,0 +1,30 @@ +// check-pass + +#![allow(irrefutable_let_patterns)] + +use std::ops::Range; + +fn _if() { + if let 0 = 1 {} + + if true && let 0 = 1 {} + + if let 0 = 1 && true {} + + if let Range { start: _, end: _ } = (true..true) && false {} + + if let 1 = 1 && let true = { true } && false { + } +} + +fn _while() { + while let 0 = 1 {} + + while true && let 0 = 1 {} + + while let 0 = 1 && true {} + + while let Range { start: _, end: _ } = (true..true) && false {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs index d851fac8e644f..82164bda4897d 100644 --- a/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs +++ b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(let_chains)] #![allow(irrefutable_let_patterns)] fn main() { diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs index a7e108d72d1ff..e0dded1521760 100644 --- a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs +++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs @@ -1,19 +1,19 @@ fn and_chain() { let z; if true && { z = 3; true} && z == 3 {} - //~^ ERROR use of possibly-uninitialized + //~^ ERROR E0381 } fn and_chain_2() { let z; true && { z = 3; true} && z == 3; - //~^ ERROR use of possibly-uninitialized + //~^ ERROR E0381 } fn or_chain() { let z; if false || { z = 3; false} || z == 3 {} - //~^ ERROR use of possibly-uninitialized + //~^ ERROR E0381 } fn main() { diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr index 3c47040cc8c24..30d5a6779fcd7 100644 --- a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr @@ -1,20 +1,32 @@ -error[E0381]: use of possibly-uninitialized variable: `z` +error[E0381]: used binding `z` is possibly-uninitialized --> $DIR/chains-without-let.rs:3:34 | +LL | let z; + | - binding declared here but left uninitialized LL | if true && { z = 3; true} && z == 3 {} - | ^ use of possibly-uninitialized `z` + | ----- ^ `z` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions -error[E0381]: use of possibly-uninitialized variable: `z` +error[E0381]: used binding `z` is possibly-uninitialized --> $DIR/chains-without-let.rs:9:31 | +LL | let z; + | - binding declared here but left uninitialized LL | true && { z = 3; true} && z == 3; - | ^ use of possibly-uninitialized `z` + | ----- ^ `z` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions -error[E0381]: use of possibly-uninitialized variable: `z` +error[E0381]: used binding `z` is possibly-uninitialized --> $DIR/chains-without-let.rs:15:36 | +LL | let z; + | - binding declared here but left uninitialized LL | if false || { z = 3; false} || z == 3 {} - | ^ use of possibly-uninitialized `z` + | ----- ^ `z` used here but it is possibly-uninitialized + | | + | binding initialized here in some conditions error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs index 1bd8b74240eac..a89c58785e358 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -17,8 +17,6 @@ // // To that end, we check some positions which is not part of the language above. -#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. - #![allow(irrefutable_let_patterns)] use std::ops::Range; @@ -28,47 +26,61 @@ fn main() {} fn _if() { if (let 0 = 1) {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement if (((let 0 = 1))) {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement if (let 0 = 1) && true {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement if true && (let 0 = 1) {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement if (let 0 = 1) && (let 0 = 1) {} //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } fn _while() { while (let 0 = 1) {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement while (((let 0 = 1))) {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement while (let 0 = 1) && true {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement while true && (let 0 = 1) {} //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement while (let 0 = 1) && (let 0 = 1) {} //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } fn _macros() { @@ -81,45 +93,78 @@ fn _macros() { use_expr!((let 0 = 1 && 0 == 0)); //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + use_expr!(true && let 0 = 1); + //~^ ERROR expected expression, found `let` statement + + macro_rules! noop_expr { ($e:expr) => {}; } + noop_expr!((let 0 = 1)); + //~^ ERROR expected expression, found `let` statement } fn nested_within_if_expr() { - if &let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types + if &let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement - if !let 0 = 0 {} //~ ERROR `let` expressions are not supported here - if *let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR type `bool` cannot be dereferenced - if -let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR cannot apply unary operator `-` to type `bool` + if !let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if *let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR type `bool` cannot be dereferenced + //~| ERROR expected expression, found `let` statement + if -let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR cannot apply unary operator `-` to type `bool` + //~| ERROR expected expression, found `let` statement fn _check_try_binds_tighter() -> Result<(), ()> { if let 0 = 0? {} //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } - if (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be applied to values that implement `Try` + if (let 0 = 0)? {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR the `?` operator can only be applied to values that implement `Try` //~| ERROR the `?` operator can only be used in a function that returns `Result` + //~| ERROR expected expression, found `let` statement - if true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here - if (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here - if true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here - if true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here + if true || let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if true && (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + if true || (true && let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here let mut x = true; - if x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types + if x = let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement - if true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types - if ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types - if (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types + if true..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + if ..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + if (let 0 = 0).. {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement // Binds as `(let ... = true)..true &&/|| false`. if let Range { start: _, end: _ } = true..true && false {} @@ -147,43 +192,70 @@ fn nested_within_if_expr() { //~| ERROR mismatched types //~| ERROR mismatched types - if let true = let true = true {} //~ ERROR `let` expressions are not supported here + if let true = let true = true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } fn nested_within_while_expr() { - while &let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types + while &let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement - while !let 0 = 0 {} //~ ERROR `let` expressions are not supported here - while *let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR type `bool` cannot be dereferenced - while -let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR cannot apply unary operator `-` to type `bool` + while !let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while *let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR type `bool` cannot be dereferenced + //~| ERROR expected expression, found `let` statement + while -let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR cannot apply unary operator `-` to type `bool` + //~| ERROR expected expression, found `let` statement fn _check_try_binds_tighter() -> Result<(), ()> { while let 0 = 0? {} //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } - while (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be applied to values that implement `Try` + while (let 0 = 0)? {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR the `?` operator can only be applied to values that implement `Try` //~| ERROR the `?` operator can only be used in a function that returns `Result` + //~| ERROR expected expression, found `let` statement - while true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here - while (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here - while true && (true || let 0 = 0) {} //~ ERROR `let` expressions are not supported here - while true || (true && let 0 = 0) {} //~ ERROR `let` expressions are not supported here + while true || let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while true && (true || let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + while true || (true && let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here let mut x = true; - while x = let 0 = 0 {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types + while x = let 0 = 0 {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement - while true..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types - while ..(let 0 = 0) {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types - while (let 0 = 0).. {} //~ ERROR `let` expressions are not supported here - //~^ ERROR mismatched types + while true..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + while ..(let 0 = 0) {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement + while (let 0 = 0).. {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement // Binds as `(let ... = true)..true &&/|| false`. while let Range { start: _, end: _ } = true..true && false {} @@ -211,7 +283,9 @@ fn nested_within_while_expr() { //~| ERROR mismatched types //~| ERROR mismatched types - while let true = let true = true {} //~ ERROR `let` expressions are not supported here + while let true = let true = true {} + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } fn not_error_because_clarified_intent() { @@ -225,45 +299,85 @@ fn not_error_because_clarified_intent() { } fn outside_if_and_while_expr() { - &let 0 = 0; //~ ERROR `let` expressions are not supported here + &let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement - !let 0 = 0; //~ ERROR `let` expressions are not supported here - *let 0 = 0; //~ ERROR `let` expressions are not supported here - //~^ ERROR type `bool` cannot be dereferenced - -let 0 = 0; //~ ERROR `let` expressions are not supported here - //~^ ERROR cannot apply unary operator `-` to type `bool` + !let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + *let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR type `bool` cannot be dereferenced + //~| ERROR expected expression, found `let` statement + -let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR cannot apply unary operator `-` to type `bool` + //~| ERROR expected expression, found `let` statement fn _check_try_binds_tighter() -> Result<(), ()> { let 0 = 0?; //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } - (let 0 = 0)?; //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be used in a function that returns `Result` + (let 0 = 0)?; + //~^ ERROR `let` expressions are not supported here + //~| ERROR the `?` operator can only be used in a function that returns `Result` //~| ERROR the `?` operator can only be applied to values that implement `Try` + //~| ERROR expected expression, found `let` statement - true || let 0 = 0; //~ ERROR `let` expressions are not supported here - (true || let 0 = 0); //~ ERROR `let` expressions are not supported here - true && (true || let 0 = 0); //~ ERROR `let` expressions are not supported here + true || let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + (true || let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + true && (true || let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement let mut x = true; - x = let 0 = 0; //~ ERROR `let` expressions are not supported here + x = let 0 = 0; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement - true..(let 0 = 0); //~ ERROR `let` expressions are not supported here - ..(let 0 = 0); //~ ERROR `let` expressions are not supported here - (let 0 = 0)..; //~ ERROR `let` expressions are not supported here + true..(let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + ..(let 0 = 0); + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + (let 0 = 0)..; + //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement (let Range { start: _, end: _ } = true..true || false); //~^ ERROR `let` expressions are not supported here //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement (let true = let true = true); //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + + { + #[cfg(FALSE)] + let x = true && let y = 1; + //~^ ERROR expected expression, found `let` statement + } + + #[cfg(FALSE)] + { + [1, 2, 3][let _ = ()] + //~^ ERROR expected expression, found `let` statement + } // Check function tail position. &let 0 = 0 //~^ ERROR `let` expressions are not supported here //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement } // Let's make sure that `let` inside const generic arguments are considered. @@ -272,15 +386,18 @@ fn inside_const_generic_arguments() { impl<const B: bool> A<{B}> { const O: u32 = 5; } if let A::<{ - true && let 1 = 1 //~ ERROR `let` expressions are not supported here + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here }>::O = 5 {} while let A::<{ - true && let 1 = 1 //~ ERROR `let` expressions are not supported here + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here }>::O = 5 {} if A::<{ - true && let 1 = 1 //~ ERROR `let` expressions are not supported here + true && let 1 = 1 + //~^ ERROR `let` expressions are not supported here }>::O == 5 {} // In the cases above we have `ExprKind::Block` to help us out. @@ -301,14 +418,18 @@ fn with_parenthesis() { if (let Some(a) = opt && true) { //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } if (let Some(a) = opt) && true { //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } if (let Some(a) = opt) && (let Some(b) = a) { //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement } if let Some(a) = opt && (true && true) { } @@ -316,13 +437,18 @@ fn with_parenthesis() { if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement } if (let Some(a) = opt && (let Some(b) = a)) && true { //~^ ERROR `let` expressions are not supported here //~| ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement } if (let Some(a) = opt && (true)) && true { //~^ ERROR `let` expressions are not supported here + //~| ERROR expected expression, found `let` statement } if (true && (true)) && let Some(a) = opt { @@ -335,4 +461,17 @@ fn with_parenthesis() { let fun = || true; if let true = (true && fun()) && (true) { } + + #[cfg(FALSE)] + let x = (true && let y = 1); + //~^ ERROR expected expression, found `let` statement + + #[cfg(FALSE)] + { + ([1, 2, 3][let _ = ()]) + //~^ ERROR expected expression, found `let` statement + } + + #[cfg(FALSE)] (let 0 = 1); + //~^ ERROR expected expression, found `let` statement } diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index f7f39bd0b9a07..5e5289f169331 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -1,5 +1,353 @@ +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:27:9 + | +LL | if (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:31:11 + | +LL | if (((let 0 = 1))) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:35:9 + | +LL | if (let 0 = 1) && true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:39:17 + | +LL | if true && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:43:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:43:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:49:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:57:12 + | +LL | while (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:61:14 + | +LL | while (((let 0 = 1))) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:65:12 + | +LL | while (let 0 = 1) && true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:69:20 + | +LL | while true && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:73:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:73:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:79:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:110:9 + | +LL | if &let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:115:9 + | +LL | if !let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:118:9 + | +LL | if *let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:122:9 + | +LL | if -let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:132:9 + | +LL | if (let 0 = 0)? {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:138:16 + | +LL | if true || let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:141:17 + | +LL | if (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:144:25 + | +LL | if true && (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:151:12 + | +LL | if x = let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:156:15 + | +LL | if true..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:160:11 + | +LL | if ..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:164:9 + | +LL | if (let 0 = 0).. {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:195:19 + | +LL | if let true = let true = true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:201:12 + | +LL | while &let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:206:12 + | +LL | while !let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:209:12 + | +LL | while *let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:213:12 + | +LL | while -let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:223:12 + | +LL | while (let 0 = 0)? {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:229:19 + | +LL | while true || let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:232:20 + | +LL | while (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:235:28 + | +LL | while true && (true || let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:242:15 + | +LL | while x = let 0 = 0 {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:247:18 + | +LL | while true..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:251:14 + | +LL | while ..(let 0 = 0) {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:255:12 + | +LL | while (let 0 = 0).. {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:286:22 + | +LL | while let true = let true = true {} + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:302:6 + | +LL | &let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:306:6 + | +LL | !let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:309:6 + | +LL | *let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:313:6 + | +LL | -let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:323:6 + | +LL | (let 0 = 0)?; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:329:13 + | +LL | true || let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:332:14 + | +LL | (true || let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:335:22 + | +LL | true && (true || let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:340:9 + | +LL | x = let 0 = 0; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:344:12 + | +LL | true..(let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:347:8 + | +LL | ..(let 0 = 0); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:350:6 + | +LL | (let 0 = 0)..; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:354:6 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:359:6 + | +LL | (let true = let true = true); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:359:17 + | +LL | (let true = let true = true); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:366:25 + | +LL | let x = true && let y = 1; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:372:19 + | +LL | [1, 2, 3][let _ = ()] + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:377:6 + | +LL | &let 0 = 0 + | ^^^ + error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:293:9 + --> $DIR/disallowed-positions.rs:410:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -9,28 +357,124 @@ help: enclose the `const` expression in braces LL | { true && let 1 = 1 } | + + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:419:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:424:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:428:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:428:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:437:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:437:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:443:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:443:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:449:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:466:22 + | +LL | let x = (true && let y = 1); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:471:20 + | +LL | ([1, 2, 3][let _ = ()]) + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:475:20 + | +LL | #[cfg(FALSE)] (let 0 = 1); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:93:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:97:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:101:23 + | +LL | use_expr!(true && let 0 = 1); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:105:17 + | +LL | noop_expr!((let 0 = 1)); + | ^^^ + error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:29:9 + --> $DIR/disallowed-positions.rs:27:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:29:9 + --> $DIR/disallowed-positions.rs:27:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:32:11 + --> $DIR/disallowed-positions.rs:31:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:32:11 + --> $DIR/disallowed-positions.rs:31:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ @@ -49,254 +493,254 @@ LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:38:17 + --> $DIR/disallowed-positions.rs:39:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:38:17 + --> $DIR/disallowed-positions.rs:39:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:41:9 + --> $DIR/disallowed-positions.rs:43:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:9 + --> $DIR/disallowed-positions.rs:43:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:41:24 + --> $DIR/disallowed-positions.rs:43:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:24 + --> $DIR/disallowed-positions.rs:43:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:45:48 + --> $DIR/disallowed-positions.rs:49:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:45:61 + --> $DIR/disallowed-positions.rs:49:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:52:12 + --> $DIR/disallowed-positions.rs:57:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:52:12 + --> $DIR/disallowed-positions.rs:57:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:55:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:55:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:61:20 + --> $DIR/disallowed-positions.rs:69:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:61:20 + --> $DIR/disallowed-positions.rs:69:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:73:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:73:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:64:27 + --> $DIR/disallowed-positions.rs:73:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:27 + --> $DIR/disallowed-positions.rs:73:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:79:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:79:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:68:51 + --> $DIR/disallowed-positions.rs:79:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:79:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:68:64 + --> $DIR/disallowed-positions.rs:79:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:79:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:81:16 + --> $DIR/disallowed-positions.rs:93:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:81:16 + --> $DIR/disallowed-positions.rs:93:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:81:16 + --> $DIR/disallowed-positions.rs:93:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:81:16 + --> $DIR/disallowed-positions.rs:93:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:84:16 + --> $DIR/disallowed-positions.rs:97:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:84:16 + --> $DIR/disallowed-positions.rs:97:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:84:16 + --> $DIR/disallowed-positions.rs:97:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:84:16 + --> $DIR/disallowed-positions.rs:97:16 | LL | use_expr!((let 0 = 1)); | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:90:9 + --> $DIR/disallowed-positions.rs:110:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -304,7 +748,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:93:9 + --> $DIR/disallowed-positions.rs:115:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -312,7 +756,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:94:9 + --> $DIR/disallowed-positions.rs:118:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -320,7 +764,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:96:9 + --> $DIR/disallowed-positions.rs:122:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -328,72 +772,72 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:104:9 + --> $DIR/disallowed-positions.rs:132:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:104:9 + --> $DIR/disallowed-positions.rs:132:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:108:16 + --> $DIR/disallowed-positions.rs:138:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:108:13 + --> $DIR/disallowed-positions.rs:138:13 | LL | if true || let 0 = 0 {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:109:17 + --> $DIR/disallowed-positions.rs:141:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:109:14 + --> $DIR/disallowed-positions.rs:141:14 | LL | if (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:110:25 + --> $DIR/disallowed-positions.rs:144:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:110:22 + --> $DIR/disallowed-positions.rs:144:22 | LL | if true && (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:111:25 + --> $DIR/disallowed-positions.rs:147:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:111:17 + --> $DIR/disallowed-positions.rs:147:17 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:114:12 + --> $DIR/disallowed-positions.rs:151:12 | LL | if x = let 0 = 0 {} | ^^^^^^^^^ @@ -401,46 +845,46 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:117:15 + --> $DIR/disallowed-positions.rs:156:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:117:15 + --> $DIR/disallowed-positions.rs:156:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:119:11 + --> $DIR/disallowed-positions.rs:160:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:119:11 + --> $DIR/disallowed-positions.rs:160:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:121:9 + --> $DIR/disallowed-positions.rs:164:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:121:9 + --> $DIR/disallowed-positions.rs:164:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:125:8 + --> $DIR/disallowed-positions.rs:170:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -448,7 +892,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:129:8 + --> $DIR/disallowed-positions.rs:174:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,7 +900,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:136:8 + --> $DIR/disallowed-positions.rs:181:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -464,7 +908,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:144:8 + --> $DIR/disallowed-positions.rs:189:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -472,7 +916,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:150:19 + --> $DIR/disallowed-positions.rs:195:19 | LL | if let true = let true = true {} | ^^^^^^^^^^^^^^^ @@ -480,7 +924,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:154:12 + --> $DIR/disallowed-positions.rs:201:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -488,7 +932,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:157:12 + --> $DIR/disallowed-positions.rs:206:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -496,7 +940,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:158:12 + --> $DIR/disallowed-positions.rs:209:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -504,7 +948,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:160:12 + --> $DIR/disallowed-positions.rs:213:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -512,72 +956,72 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:168:12 + --> $DIR/disallowed-positions.rs:223:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:168:12 + --> $DIR/disallowed-positions.rs:223:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:172:19 + --> $DIR/disallowed-positions.rs:229:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:172:16 + --> $DIR/disallowed-positions.rs:229:16 | LL | while true || let 0 = 0 {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:173:20 + --> $DIR/disallowed-positions.rs:232:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:173:17 + --> $DIR/disallowed-positions.rs:232:17 | LL | while (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:174:28 + --> $DIR/disallowed-positions.rs:235:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:174:25 + --> $DIR/disallowed-positions.rs:235:25 | LL | while true && (true || let 0 = 0) {} | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:175:28 + --> $DIR/disallowed-positions.rs:238:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:175:20 + --> $DIR/disallowed-positions.rs:238:20 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:178:15 + --> $DIR/disallowed-positions.rs:242:15 | LL | while x = let 0 = 0 {} | ^^^^^^^^^ @@ -585,46 +1029,46 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:181:18 + --> $DIR/disallowed-positions.rs:247:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:181:18 + --> $DIR/disallowed-positions.rs:247:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:183:14 + --> $DIR/disallowed-positions.rs:251:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:183:14 + --> $DIR/disallowed-positions.rs:251:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:185:12 + --> $DIR/disallowed-positions.rs:255:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:185:12 + --> $DIR/disallowed-positions.rs:255:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:189:11 + --> $DIR/disallowed-positions.rs:261:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -632,7 +1076,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:193:11 + --> $DIR/disallowed-positions.rs:265:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -640,7 +1084,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:200:11 + --> $DIR/disallowed-positions.rs:272:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -648,7 +1092,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:208:11 + --> $DIR/disallowed-positions.rs:280:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -656,7 +1100,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:214:22 + --> $DIR/disallowed-positions.rs:286:22 | LL | while let true = let true = true {} | ^^^^^^^^^^^^^^^ @@ -664,7 +1108,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:228:6 + --> $DIR/disallowed-positions.rs:302:6 | LL | &let 0 = 0; | ^^^^^^^^^ @@ -672,7 +1116,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:230:6 + --> $DIR/disallowed-positions.rs:306:6 | LL | !let 0 = 0; | ^^^^^^^^^ @@ -680,7 +1124,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:231:6 + --> $DIR/disallowed-positions.rs:309:6 | LL | *let 0 = 0; | ^^^^^^^^^ @@ -688,7 +1132,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:233:6 + --> $DIR/disallowed-positions.rs:313:6 | LL | -let 0 = 0; | ^^^^^^^^^ @@ -696,59 +1140,59 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:241:6 + --> $DIR/disallowed-positions.rs:323:6 | LL | (let 0 = 0)?; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:241:6 + --> $DIR/disallowed-positions.rs:323:6 | LL | (let 0 = 0)?; | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:245:13 + --> $DIR/disallowed-positions.rs:329:13 | LL | true || let 0 = 0; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:245:10 + --> $DIR/disallowed-positions.rs:329:10 | LL | true || let 0 = 0; | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:246:14 + --> $DIR/disallowed-positions.rs:332:14 | LL | (true || let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:246:11 + --> $DIR/disallowed-positions.rs:332:11 | LL | (true || let 0 = 0); | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:247:22 + --> $DIR/disallowed-positions.rs:335:22 | LL | true && (true || let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:247:19 + --> $DIR/disallowed-positions.rs:335:19 | LL | true && (true || let 0 = 0); | ^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:250:9 + --> $DIR/disallowed-positions.rs:340:9 | LL | x = let 0 = 0; | ^^^^^^^^^ @@ -756,46 +1200,46 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:252:12 + --> $DIR/disallowed-positions.rs:344:12 | LL | true..(let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:252:12 + --> $DIR/disallowed-positions.rs:344:12 | LL | true..(let 0 = 0); | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:253:8 + --> $DIR/disallowed-positions.rs:347:8 | LL | ..(let 0 = 0); | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:253:8 + --> $DIR/disallowed-positions.rs:347:8 | LL | ..(let 0 = 0); | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:254:6 + --> $DIR/disallowed-positions.rs:350:6 | LL | (let 0 = 0)..; | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:254:6 + --> $DIR/disallowed-positions.rs:350:6 | LL | (let 0 = 0)..; | ^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:256:6 + --> $DIR/disallowed-positions.rs:354:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -803,20 +1247,20 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:260:6 + --> $DIR/disallowed-positions.rs:359:6 | LL | (let true = let true = true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:260:6 + --> $DIR/disallowed-positions.rs:359:6 | LL | (let true = let true = true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:264:6 + --> $DIR/disallowed-positions.rs:377:6 | LL | &let 0 = 0 | ^^^^^^^^^ @@ -824,7 +1268,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:275:17 + --> $DIR/disallowed-positions.rs:389:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -832,7 +1276,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:279:17 + --> $DIR/disallowed-positions.rs:394:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -840,7 +1284,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:283:17 + --> $DIR/disallowed-positions.rs:399:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -848,7 +1292,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:293:17 + --> $DIR/disallowed-positions.rs:410:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -856,124 +1300,124 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:302:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:302:9 + --> $DIR/disallowed-positions.rs:419:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:306:9 + --> $DIR/disallowed-positions.rs:424:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:306:9 + --> $DIR/disallowed-positions.rs:424:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:309:9 + --> $DIR/disallowed-positions.rs:428:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:309:9 + --> $DIR/disallowed-positions.rs:428:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:309:32 + --> $DIR/disallowed-positions.rs:428:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:309:32 + --> $DIR/disallowed-positions.rs:428:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:316:9 + --> $DIR/disallowed-positions.rs:437:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:316:9 + --> $DIR/disallowed-positions.rs:437:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:316:31 + --> $DIR/disallowed-positions.rs:437:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:316:31 + --> $DIR/disallowed-positions.rs:437:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:320:9 + --> $DIR/disallowed-positions.rs:443:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:320:9 + --> $DIR/disallowed-positions.rs:443:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:320:31 + --> $DIR/disallowed-positions.rs:443:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:320:31 + --> $DIR/disallowed-positions.rs:443:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:324:9 + --> $DIR/disallowed-positions.rs:449:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:324:9 + --> $DIR/disallowed-positions.rs:449:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:90:8 + --> $DIR/disallowed-positions.rs:110:8 | LL | if &let 0 = 0 {} | ^^^^^^^^^^ expected `bool`, found `&bool` @@ -985,19 +1429,19 @@ LL + if let 0 = 0 {} | error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:94:8 + --> $DIR/disallowed-positions.rs:118:8 | LL | if *let 0 = 0 {} | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:96:8 + --> $DIR/disallowed-positions.rs:122:8 | LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:104:8 + --> $DIR/disallowed-positions.rs:132:8 | LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -1005,7 +1449,7 @@ LL | if (let 0 = 0)? {} = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:104:19 + --> $DIR/disallowed-positions.rs:132:19 | LL | / fn nested_within_if_expr() { LL | | if &let 0 = 0 {} @@ -1015,14 +1459,14 @@ LL | | LL | | if (let 0 = 0)? {} | | ^ cannot use the `?` operator in a function that returns `()` ... | -LL | | if let true = let true = true {} +LL | | LL | | } | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:114:8 + --> $DIR/disallowed-positions.rs:151:8 | LL | if x = let 0 = 0 {} | ^^^^^^^^^^^^^ expected `bool`, found `()` @@ -1033,7 +1477,7 @@ LL | if x == let 0 = 0 {} | ~~ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:117:8 + --> $DIR/disallowed-positions.rs:156:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1042,7 +1486,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:119:8 + --> $DIR/disallowed-positions.rs:160:8 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` @@ -1051,7 +1495,7 @@ LL | if ..(let 0 = 0) {} found struct `RangeTo<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:121:8 + --> $DIR/disallowed-positions.rs:164:8 | LL | if (let 0 = 0).. {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` @@ -1060,7 +1504,7 @@ LL | if (let 0 = 0).. {} found struct `RangeFrom<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:125:12 + --> $DIR/disallowed-positions.rs:170:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1071,7 +1515,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:125:8 + --> $DIR/disallowed-positions.rs:170:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1080,7 +1524,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:129:12 + --> $DIR/disallowed-positions.rs:174:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1091,7 +1535,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:129:8 + --> $DIR/disallowed-positions.rs:174:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1100,7 +1544,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:136:12 + --> $DIR/disallowed-positions.rs:181:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1111,20 +1555,20 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:136:41 + --> $DIR/disallowed-positions.rs:181:41 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]` + found closure `[closure@$DIR/disallowed-positions.rs:181:41: 181:43]` help: use parentheses to call this closure | LL | if let Range { start: F, end } = F..(|| true)() {} | + +++ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:136:8 + --> $DIR/disallowed-positions.rs:181:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1133,7 +1577,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:144:12 + --> $DIR/disallowed-positions.rs:189:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1144,7 +1588,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:144:44 + --> $DIR/disallowed-positions.rs:189:44 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^ expected `bool`, found `&&bool` @@ -1156,7 +1600,7 @@ LL + if let Range { start: true, end } = t..false {} | error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:144:8 + --> $DIR/disallowed-positions.rs:189:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1165,7 +1609,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<bool>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:100:20 + --> $DIR/disallowed-positions.rs:128:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1173,7 +1617,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:154:11 + --> $DIR/disallowed-positions.rs:201:11 | LL | while &let 0 = 0 {} | ^^^^^^^^^^ expected `bool`, found `&bool` @@ -1185,19 +1629,19 @@ LL + while let 0 = 0 {} | error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:158:11 + --> $DIR/disallowed-positions.rs:209:11 | LL | while *let 0 = 0 {} | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:160:11 + --> $DIR/disallowed-positions.rs:213:11 | LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:168:11 + --> $DIR/disallowed-positions.rs:223:11 | LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -1205,7 +1649,7 @@ LL | while (let 0 = 0)? {} = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:168:22 + --> $DIR/disallowed-positions.rs:223:22 | LL | / fn nested_within_while_expr() { LL | | while &let 0 = 0 {} @@ -1215,14 +1659,14 @@ LL | | LL | | while (let 0 = 0)? {} | | ^ cannot use the `?` operator in a function that returns `()` ... | -LL | | while let true = let true = true {} +LL | | LL | | } | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:178:11 + --> $DIR/disallowed-positions.rs:242:11 | LL | while x = let 0 = 0 {} | ^^^^^^^^^^^^^ expected `bool`, found `()` @@ -1233,7 +1677,7 @@ LL | while x == let 0 = 0 {} | ~~ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:181:11 + --> $DIR/disallowed-positions.rs:247:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1242,7 +1686,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:183:11 + --> $DIR/disallowed-positions.rs:251:11 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` @@ -1251,7 +1695,7 @@ LL | while ..(let 0 = 0) {} found struct `RangeTo<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:185:11 + --> $DIR/disallowed-positions.rs:255:11 | LL | while (let 0 = 0).. {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` @@ -1260,7 +1704,7 @@ LL | while (let 0 = 0).. {} found struct `RangeFrom<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:189:15 + --> $DIR/disallowed-positions.rs:261:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1271,7 +1715,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:189:11 + --> $DIR/disallowed-positions.rs:261:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1280,7 +1724,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:193:15 + --> $DIR/disallowed-positions.rs:265:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1291,7 +1735,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:193:11 + --> $DIR/disallowed-positions.rs:265:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1300,7 +1744,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:200:15 + --> $DIR/disallowed-positions.rs:272:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1311,20 +1755,20 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:200:44 + --> $DIR/disallowed-positions.rs:272:44 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]` + found closure `[closure@$DIR/disallowed-positions.rs:272:44: 272:46]` help: use parentheses to call this closure | LL | while let Range { start: F, end } = F..(|| true)() {} | + +++ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:200:11 + --> $DIR/disallowed-positions.rs:272:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1333,7 +1777,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<bool>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:208:15 + --> $DIR/disallowed-positions.rs:280:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1344,7 +1788,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:208:47 + --> $DIR/disallowed-positions.rs:280:47 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^ expected `bool`, found `&&bool` @@ -1356,7 +1800,7 @@ LL + while let Range { start: true, end } = t..false {} | error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:208:11 + --> $DIR/disallowed-positions.rs:280:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -1365,7 +1809,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<bool>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:164:23 + --> $DIR/disallowed-positions.rs:219:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1373,19 +1817,19 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:231:5 + --> $DIR/disallowed-positions.rs:309:5 | LL | *let 0 = 0; | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:233:5 + --> $DIR/disallowed-positions.rs:313:5 | LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:241:5 + --> $DIR/disallowed-positions.rs:323:5 | LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -1393,12 +1837,12 @@ LL | (let 0 = 0)?; = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:241:16 + --> $DIR/disallowed-positions.rs:323:16 | LL | / fn outside_if_and_while_expr() { LL | | &let 0 = 0; LL | | -LL | | !let 0 = 0; +LL | | ... | LL | | (let 0 = 0)?; | | ^ cannot use the `?` operator in a function that returns `()` @@ -1410,7 +1854,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:256:10 + --> $DIR/disallowed-positions.rs:354:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1421,7 +1865,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:264:5 + --> $DIR/disallowed-positions.rs:377:5 | LL | fn outside_if_and_while_expr() { | - help: try adding a return type: `-> &bool` @@ -1430,14 +1874,14 @@ LL | &let 0 = 0 | ^^^^^^^^^^ expected `()`, found `&bool` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:237:17 + --> $DIR/disallowed-positions.rs:319:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 134 previous errors +error: aborting due to 208 previous errors Some errors have detailed explanations: E0277, E0308, E0600, E0614. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs index e66caa19ec96b..deef4240d4da7 100644 --- a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs +++ b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, let_else)] +#![feature(let_else)] fn main() { let opt = Some(1i32); @@ -17,6 +17,7 @@ fn main() { //~| ERROR `let` expressions are not supported here //~| ERROR mismatched types //~| ERROR mismatched types + //~| ERROR expected expression, found `let` statement return; }; diff --git a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr index eea8ed0c9633e..498a112fa9bb3 100644 --- a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr @@ -9,6 +9,12 @@ help: wrap the expression in parentheses LL | let Some(n) = (opt && n == 1) else { | + + +error: expected expression, found `let` statement + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26 + | +LL | let Some(n) = opt && let another = n else { + | ^^^ + error: a `&&` expression cannot be directly assigned in `let...else` --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19 | @@ -21,43 +27,43 @@ LL | let Some(n) = (opt && let another = n) else { | + + error: this `if` expression is missing a block after the condition - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:5 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5 | LL | if let Some(n) = opt else { | ^^ | help: add a block here - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:25 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:25 | LL | if let Some(n) = opt else { | ^ error: this `if` expression is missing a block after the condition - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:5 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5 | LL | if let Some(n) = opt && n == 1 else { | ^^ | help: add a block here - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:35 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:35 | LL | if let Some(n) = opt && n == 1 else { | ^ error: this `if` expression is missing a block after the condition - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:5 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:32:5 | LL | if let Some(n) = opt && let another = n else { | ^^ | help: add a block here - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:44 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:32:44 | LL | if let Some(n) = opt && let another = n else { | ^ error: expected `{`, found keyword `else` - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:37:33 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:38:33 | LL | while let Some(n) = opt else { | ----- ----------------- ^^^^ expected `{` @@ -66,7 +72,7 @@ LL | while let Some(n) = opt else { | while parsing the body of this `while` expression error: expected `{`, found keyword `else` - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:43:43 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:44:43 | LL | while let Some(n) = opt && n == 1 else { | ----- --------------------------- ^^^^ expected `{` @@ -75,7 +81,7 @@ LL | while let Some(n) = opt && n == 1 else { | while parsing the body of this `while` expression error: expected `{`, found keyword `else` - --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:49:52 + --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:50:52 | LL | while let Some(n) = opt && let another = n else { | ----- ------------------------------------ ^^^^ expected `{` @@ -131,6 +137,6 @@ LL | let Some(n) = opt && let another = n else { = note: expected type `bool` found enum `Option<_>` -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs deleted file mode 100644 index ac60bc7e57fd4..0000000000000 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs +++ /dev/null @@ -1,56 +0,0 @@ -// gate-test-let_chains - -// Here we test feature gating for ´let_chains`. -// See `disallowed-positions.rs` for the grammar -// defining the language for gated allowed positions. - -#![allow(irrefutable_let_patterns)] - -use std::ops::Range; - -fn _if() { - if let 0 = 1 {} // Stable! - - if true && let 0 = 1 {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - if let 0 = 1 && true {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - if let Range { start: _, end: _ } = (true..true) && false {} - //~^ ERROR `let` expressions in this position are unstable [E0658] -} - -fn _while() { - while let 0 = 1 {} // Stable! - - while true && let 0 = 1 {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - while let 0 = 1 && true {} - //~^ ERROR `let` expressions in this position are unstable [E0658] - - while let Range { start: _, end: _ } = (true..true) && false {} - //~^ ERROR `let` expressions in this position are unstable [E0658] -} - -fn _macros() { - macro_rules! noop_expr { ($e:expr) => {}; } - - noop_expr!((let 0 = 1)); - //~^ ERROR `let` expressions in this position are unstable [E0658] - - macro_rules! use_expr { - ($e:expr) => { - if $e {} - while $e {} - } - } - #[cfg(FALSE)] (let 0 = 1); - //~^ ERROR `let` expressions in this position are unstable [E0658] - use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` - // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`. -} - -fn main() {} diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr deleted file mode 100644 index 1eabee47c64ac..0000000000000 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr +++ /dev/null @@ -1,84 +0,0 @@ -error: no rules expected the token `let` - --> $DIR/feature-gate.rs:51:15 - | -LL | macro_rules! use_expr { - | --------------------- when calling this macro -... -LL | use_expr!(let 0 = 1); - | ^^^ no rules expected this token in macro call - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:14:16 - | -LL | if true && let 0 = 1 {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:17:8 - | -LL | if let 0 = 1 && true {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:20:8 - | -LL | if let Range { start: _, end: _ } = (true..true) && false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:27:19 - | -LL | while true && let 0 = 1 {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:30:11 - | -LL | while let 0 = 1 && true {} - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:33:11 - | -LL | while let Range { start: _, end: _ } = (true..true) && false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:49:20 - | -LL | #[cfg(FALSE)] (let 0 = 1); - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error[E0658]: `let` expressions in this position are unstable - --> $DIR/feature-gate.rs:40:17 - | -LL | noop_expr!((let 0 = 1)); - | ^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs new file mode 100644 index 0000000000000..7bc6d43a7276a --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs @@ -0,0 +1,43 @@ +fn main() { + let _opt = Some(1i32); + + #[cfg(FALSE)] + { + let _ = &&let Some(x) = Some(42); + //~^ ERROR expected expression, found `let` statement + } + #[cfg(FALSE)] + { + if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { + //~^ ERROR expected expression, found `let` statement + //~| ERROR expected expression, found `let` statement + true + } + } + + #[cfg(FALSE)] + { + if let Some(elem) = _opt && { + [1, 2, 3][let _ = ()]; + //~^ ERROR expected expression, found `let` statement + true + } { + } + } + + #[cfg(FALSE)] + { + if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { + //~^ ERROR expected expression, found `let` statement + true + } + } + #[cfg(FALSE)] + { + if let a = 1 && { + let x = let y = 1; + //~^ ERROR expected expression, found `let` statement + } { + } + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr b/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr new file mode 100644 index 0000000000000..d1552a0b2d5ad --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr @@ -0,0 +1,38 @@ +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:6:19 + | +LL | let _ = &&let Some(x) = Some(42); + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:11:47 + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:11:57 + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:21:23 + | +LL | [1, 2, 3][let _ = ()]; + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:30:47 + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { + | ^^^ + +error: expected expression, found `let` statement + --> $DIR/invalid-let-in-a-valid-let-context.rs:38:21 + | +LL | let x = let y = 1; + | ^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs index 3d1626e8ffb9a..1ef4bc56e5252 100644 --- a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs +++ b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs @@ -1,7 +1,7 @@ // revisions: allowed disallowed //[allowed] check-pass -#![feature(if_let_guard, let_chains)] +#![feature(if_let_guard)] #![cfg_attr(allowed, allow(irrefutable_let_patterns))] #![cfg_attr(disallowed, deny(irrefutable_let_patterns))] diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs index 6b7d883565085..34302ba96d3a2 100644 --- a/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs +++ b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(let_chains)] - fn main() { let x = Some(vec!["test"]); diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs index 7c7e31f4db400..6938062fa35f0 100644 --- a/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs +++ b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(let_chains)] - fn main() { let opt = Some("foo bar"); diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs b/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs index f90b9ab0d40f0..f6de37867d855 100644 --- a/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs +++ b/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs @@ -2,7 +2,6 @@ fn main() { match true { _ if let true = true && true => {} //~^ ERROR `if let` guards are - //~| ERROR `let` expressions in this _ => {} } } diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr b/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr index b25f299a2190f..0d620df96f610 100644 --- a/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr @@ -8,15 +8,6 @@ LL | _ if let true = true && true => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` -error[E0658]: `let` expressions in this position are unstable - --> $DIR/issue-93150.rs:3:14 - | -LL | _ if let true = true && true => {} - | ^^^^^^^^^^^^^^^ - | - = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information - = help: add `#![feature(let_chains)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs index e061174f667d9..beaca33d56364 100644 --- a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs +++ b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(if_let_guard, let_chains)] +#![feature(if_let_guard)] fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool { if let Some(first) = opt diff --git a/src/test/ui/runtime/backtrace-debuginfo.rs b/src/test/ui/runtime/backtrace-debuginfo.rs index b976c3a13bd59..7c9f1a7f2f49b 100644 --- a/src/test/ui/runtime/backtrace-debuginfo.rs +++ b/src/test/ui/runtime/backtrace-debuginfo.rs @@ -8,6 +8,7 @@ // compile-flags:-g -Copt-level=0 -Cllvm-args=-enable-tail-merge=0 // compile-flags:-Cforce-frame-pointers=yes +// compile-flags:-Cstrip=none // ignore-pretty issue #37195 // ignore-emscripten spawning processes is not supported // ignore-sgx no processes diff --git a/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr b/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr index 53272abccbbf0..b52720ae3d9de 100644 --- a/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr +++ b/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr @@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `deserialize` found for struc --> $DIR/issue-87932.rs:13:8 | LL | pub struct A {} - | ------------ function or associated item `deserialize` not found for this + | ------------ function or associated item `deserialize` not found for this struct ... LL | A::deserialize(); | ^^^^^^^^^^^ function or associated item not found in `A` diff --git a/src/test/ui/rustdoc/doc_keyword.rs b/src/test/ui/rustdoc/doc_keyword.rs index 43b84e5018cda..68a8802b2f645 100644 --- a/src/test/ui/rustdoc/doc_keyword.rs +++ b/src/test/ui/rustdoc/doc_keyword.rs @@ -15,6 +15,6 @@ fn foo() {} // Regression test for the ICE described in #83512. trait Foo { #[doc(keyword = "match")] - //~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules + //~^ ERROR: `#[doc(keyword = "...")]` should be used on modules fn quux() {} } diff --git a/src/test/ui/rustdoc/doc_keyword.stderr b/src/test/ui/rustdoc/doc_keyword.stderr index 6ba7034d54122..a1d0e4ffc0938 100644 --- a/src/test/ui/rustdoc/doc_keyword.stderr +++ b/src/test/ui/rustdoc/doc_keyword.stderr @@ -1,16 +1,16 @@ -error: `#[doc(keyword = "...")]` can only be used on empty modules +error: `#[doc(keyword = "...")]` should be used on empty modules --> $DIR/doc_keyword.rs:6:7 | LL | #[doc(keyword = "hell")] | ^^^^^^^^^^^^^^^^ -error: `#[doc(keyword = "...")]` can only be used on modules +error: `#[doc(keyword = "...")]` should be used on modules --> $DIR/doc_keyword.rs:11:7 | LL | #[doc(keyword = "hall")] | ^^^^^^^^^^^^^^^^ -error: `#[doc(keyword = "...")]` can only be used on modules +error: `#[doc(keyword = "...")]` should be used on modules --> $DIR/doc_keyword.rs:17:11 | LL | #[doc(keyword = "match")] diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr index a0ef7e3f2cbab..3c7cccfc9a16e 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope --> $DIR/point-at-arbitrary-self-type-method.rs:8:7 | LL | struct A; - | --------- method `foo` not found for this + | -------- method `foo` not found for this struct ... LL | fn foo(self: Box<Self>) {} | --- the method is available for `Box<A>` here diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr index 440676482835c..366c14f7616a3 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -6,7 +6,7 @@ LL | trait B { fn foo(self: Box<Self>); } | | | the method is available for `Box<A>` here LL | struct A; - | --------- method `foo` not found for this + | -------- method `foo` not found for this struct ... LL | A.foo() | ^^^ method not found in `A` diff --git a/src/test/ui/simd/type-len.stderr b/src/test/ui/simd/type-len.stderr index f122d8bb0dc67..2a6bd1b0fd58a 100644 --- a/src/test/ui/simd/type-len.stderr +++ b/src/test/ui/simd/type-len.stderr @@ -2,37 +2,37 @@ error[E0075]: SIMD vector cannot be empty --> $DIR/type-len.rs:6:1 | LL | struct empty; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0075]: SIMD vector cannot be empty --> $DIR/type-len.rs:9:1 | LL | struct empty2([f32; 0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error[E0076]: SIMD vector should be homogeneous --> $DIR/type-len.rs:15:1 | LL | struct i64f64(i64, f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^ SIMD elements must have the same type + | ^^^^^^^^^^^^^ SIMD elements must have the same type error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type --> $DIR/type-len.rs:20:1 | LL | struct FooV(Foo, Foo); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type --> $DIR/type-len.rs:23:1 | LL | struct FooV2([Foo; 2]); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error[E0075]: SIMD vector cannot have more than 32768 elements --> $DIR/type-len.rs:26:1 | LL | struct TooBig([f32; 65536]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index b4693b7242ae4..6b43801b5e074 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -29,17 +29,14 @@ LL | f.f.call_mut(()) error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13 | -LL | let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| { - | ----- captured outer variable +LL | let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| { + | ----- captured outer variable ... -LL | f(Box::new(|a| { - | ________________- -LL | | -LL | | foo(f); - | | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait -LL | | -LL | | }), 3); - | |_____- captured by this `FnMut` closure +LL | f(Box::new(|a| { + | --- captured by this `FnMut` closure +LL | +LL | foo(f); + | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58]`, which does not implement the `Copy` trait error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs index 4744f3710ce53..6240f103c99b0 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs @@ -20,7 +20,7 @@ fn f() { //~^ ERROR temporary value dropped while borrowed //~| NOTE creates a temporary which is freed while still in use //~| NOTE temporary value is freed at the end of this statement - //~| NOTE consider using a `let` binding to create a longer lived value + //~| HELP consider using a `let` binding to create a longer lived value { @@ -41,7 +41,7 @@ fn f() { //~^ ERROR temporary value dropped while borrowed //~| NOTE creates a temporary which is freed while still in use //~| NOTE temporary value is freed at the end of this statement - //~| NOTE consider using a `let` binding to create a longer lived value + //~| HELP consider using a `let` binding to create a longer lived value v1.push(&old[0]); diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index 7c5caba6eae32..a236dab3ae562 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -21,7 +21,11 @@ LL | v3.push(&id('x')); // statement 6 LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id('x'); +LL ~ v3.push(&binding); // statement 6 + | error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:29:18 @@ -47,7 +51,11 @@ LL | v5.push(&id('z')); LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id('z'); +LL ~ v5.push(&binding); + | error: aborting due to 4 previous errors diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.fixed b/src/test/ui/span/borrowck-ref-into-rvalue.fixed new file mode 100644 index 0000000000000..51f65e5345d2a --- /dev/null +++ b/src/test/ui/span/borrowck-ref-into-rvalue.fixed @@ -0,0 +1,13 @@ +// run-rustfix +fn main() { + let msg; + let binding = Some("Hello".to_string()); + match binding { + //~^ ERROR temporary value dropped while borrowed + Some(ref m) => { + msg = m; + }, + None => { panic!() } + } + println!("{}", *msg); +} diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.rs b/src/test/ui/span/borrowck-ref-into-rvalue.rs index c11aa1af54095..7b09fad927fdf 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.rs +++ b/src/test/ui/span/borrowck-ref-into-rvalue.rs @@ -1,3 +1,4 @@ +// run-rustfix fn main() { let msg; match Some("Hello".to_string()) { diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.stderr index 4f529ce9511db..cb5289d24b4fc 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.stderr +++ b/src/test/ui/span/borrowck-ref-into-rvalue.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-ref-into-rvalue.rs:3:11 + --> $DIR/borrowck-ref-into-rvalue.rs:4:11 | LL | match Some("Hello".to_string()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use @@ -9,7 +9,11 @@ LL | } LL | println!("{}", *msg); | ---- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Some("Hello".to_string()); +LL ~ match binding { + | error: aborting due to previous error diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs new file mode 100644 index 0000000000000..b280c8ab6e2b2 --- /dev/null +++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs @@ -0,0 +1,18 @@ +// compile-flags: -Wrust-2021-incompatible-closure-captures + +pub struct A {} + +impl A { + async fn create(path: impl AsRef<std::path::Path>) { //~ ERROR `async fn` is not permitted in Rust 2015 + //~^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures] + ; + crate(move || {} ).await //~ ERROR expected function, found module `crate` + } +} + +trait C{async fn new(val: T) {} //~ ERROR `async fn` is not permitted in Rust 2015 +//~^ ERROR functions in traits cannot be declared `async` +//~^^ ERROR cannot find type `T` in this scope +//~^^^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures] + +//~ ERROR this file contains an unclosed delimiter diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr new file mode 100644 index 0000000000000..50de2322907ed --- /dev/null +++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr @@ -0,0 +1,93 @@ +error: this file contains an unclosed delimiter + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:18:53 + | +LL | trait C{async fn new(val: T) {} + | - unclosed delimiter +... +LL | + | ^ + +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:5 + | +LL | async fn create(path: impl AsRef<std::path::Path>) { + | ^^^^^ 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/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9 + | +LL | trait C{async fn new(val: T) {} + | ^^^^^ 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/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9 + | +LL | trait C{async fn new(val: T) {} + | -----^^^^^^^^^^^^^^^^^^ + | | + | `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 + +error[E0423]: expected function, found module `crate` + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:9:5 + | +LL | crate(move || {} ).await + | ^^^^^ not a function + +error[E0412]: cannot find type `T` in this scope + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:27 + | +LL | pub struct A {} + | ------------ similarly named struct `A` defined here +... +LL | trait C{async fn new(val: T) {} + | ^ help: a struct with a similar name exists: `A` + +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:57 + | +LL | async fn create(path: impl AsRef<std::path::Path>) { + | _____________________----_____________________________-__^ + | | | | + | | | in Rust 2018, `path` is dropped here along with the closure, but in Rust 2021 `path` is not part of the closure + | | in Rust 2018, this causes the closure to capture `path`, but in Rust 2021, it has no effect +LL | | +LL | | ; +LL | | crate(move || {} ).await +LL | | } + | |_____^ + | + = note: requested on the command line with `-W rust-2021-incompatible-closure-captures` + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html> +help: add a dummy let to cause `path` to be fully captured + | +LL | async fn create(path: impl AsRef<std::path::Path>) { let _ = &path; + | ++++++++++++++ + +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30 + | +LL | trait C{async fn new(val: T) {} + | --- - ^^ + | | | + | | in Rust 2018, `val` is dropped here along with the closure, but in Rust 2021 `val` is not part of the closure + | in Rust 2018, this causes the closure to capture `val`, but in Rust 2021, it has no effect + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html> +help: add a dummy let to cause `val` to be fully captured + | +LL | trait C{async fn new(val: T) { let _ = &val;} + | +++++++++++++ + +error: aborting due to 6 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0412, E0423, E0670, E0706. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs new file mode 100644 index 0000000000000..a776e5089075c --- /dev/null +++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs @@ -0,0 +1,15 @@ +// compile-flags -Wrust-2021-incompatible-closure-captures + +fn main() {} + +pub(crate) struct Numberer {} + +impl Numberer { + pub(crate) async fn new( + //~^ ERROR `async fn` is not permitted in Rust 2015 + interval: Duration, + //~^ ERROR cannot find type `Duration` in this scope + ) -> Numberer { + Numberer {} + } +} diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr new file mode 100644 index 0000000000000..37b2f4138603d --- /dev/null +++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -0,0 +1,24 @@ +error[E0670]: `async fn` is not permitted in Rust 2015 + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:8:16 + | +LL | pub(crate) async fn new( + | ^^^^^ 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[E0412]: cannot find type `Duration` in this scope + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:19 + | +LL | interval: Duration, + | ^^^^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::time::Duration; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0412, E0670. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 82ef13f3362d4..f919092f9ee92 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -38,7 +38,7 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST` --> $DIR/impl-wrong-item-for-trait.rs:19:1 | LL | const MY_CONST: u32; - | -------------------- `MY_CONST` from trait + | ------------------- `MY_CONST` from trait ... LL | impl Foo for FooMethodForConst { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `MY_CONST` in implementation diff --git a/src/test/ui/span/issue-15480.fixed b/src/test/ui/span/issue-15480.fixed new file mode 100644 index 0000000000000..e6d1a4dd32806 --- /dev/null +++ b/src/test/ui/span/issue-15480.fixed @@ -0,0 +1,14 @@ +// run-rustfix +fn id<T>(x: T) -> T { x } + +fn main() { + let binding = id(3); + let v = vec![ + &binding + ]; + //~^^ ERROR temporary value dropped while borrowed + + for &&x in &v { + println!("{}", x + 3); + } +} diff --git a/src/test/ui/span/issue-15480.rs b/src/test/ui/span/issue-15480.rs index b286d94178a1e..916ce4b1edb26 100644 --- a/src/test/ui/span/issue-15480.rs +++ b/src/test/ui/span/issue-15480.rs @@ -1,3 +1,4 @@ +// run-rustfix fn id<T>(x: T) -> T { x } fn main() { diff --git a/src/test/ui/span/issue-15480.stderr b/src/test/ui/span/issue-15480.stderr index 23ee2256dd85b..460ad9ac74445 100644 --- a/src/test/ui/span/issue-15480.stderr +++ b/src/test/ui/span/issue-15480.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-15480.rs:5:10 + --> $DIR/issue-15480.rs:6:10 | LL | &id(3) | ^^^^^ creates a temporary which is freed while still in use @@ -9,7 +9,12 @@ LL | ]; LL | for &&x in &v { | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id(3); +LL ~ let v = vec![ +LL ~ &binding + | error: aborting due to previous error diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 68da9f0dc88ba..e676d7372e891 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -54,7 +54,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | LL | foo(Some(42), 2, ""); - | ^^^ -- argument unexpected + | ^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/issue-34264.rs:1:4 @@ -84,7 +84,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | LL | bar(1, 2, 3); - | ^^^ - argument unexpected + | ^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/issue-34264.rs:3:4 diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index e0cfe04cf418e..eea94643e0a0a 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -29,14 +29,8 @@ LL | enum World { note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Add<Rhs = Self> { -LL | | /// The resulting type after applying the `+` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn add(self, rhs: Rhs) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Add<Rhs = Self> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0369]: cannot add `String` to `&str` --> $DIR/issue-39018.rs:11:22 diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr index cd3ffdc6f9d60..2b17899085020 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.full.stderr @@ -3,8 +3,9 @@ error[E0282]: type annotations needed | LL | let x: Option<_> = None; | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` +LL | x.unwrap().method_that_could_exist_on_some_type(); + | ---------- type must be known at this point | - = note: type must be known at this point help: consider specifying the generic argument | LL | let x: Option<_> = None::<T>; @@ -16,7 +17,6 @@ error[E0282]: type annotations needed LL | .sum::<_>() | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum` | - = note: type must be known at this point help: consider specifying the generic argument | LL | .sum::<_>() diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr index b6a3f07f5715f..d93d54e878bc8 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.generic_arg.stderr @@ -3,8 +3,9 @@ error[E0282]: type annotations needed | LL | let x: Option<_> = None; | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` +LL | x.unwrap().method_that_could_exist_on_some_type(); + | ---------- type must be known at this point | - = note: type must be known at this point help: consider specifying the generic argument | LL | let x: Option<_> = None::<T>; @@ -16,7 +17,6 @@ error[E0282]: type annotations needed LL | .sum::<_>() | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum` | - = note: type must be known at this point help: consider specifying the generic argument | LL | .sum::<S>() diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 783f5aca41746..4f30edb3f89d3 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -42,7 +42,7 @@ error[E0599]: no method named `fff` found for struct `Myisize` in the current sc --> $DIR/issue-7575.rs:62:30 | LL | struct Myisize(isize); - | ---------------------- method `fff` not found for this + | -------------- method `fff` not found for this struct ... LL | u.f8(42) + u.f9(342) + m.fff(42) | --^^^ @@ -60,6 +60,8 @@ LL | fn fff(i: isize) -> isize { error[E0599]: no method named `is_str` found for type parameter `T` in the current scope --> $DIR/issue-7575.rs:70:7 | +LL | fn param_bound<T: ManyImplTrait>(t: T) -> bool { + | - method `is_str` not found for this type parameter LL | t.is_str() | ^^^^^^ this is an associated function, not a method | diff --git a/src/test/ui/span/macro-span-replacement.stderr b/src/test/ui/span/macro-span-replacement.stderr index 433d02dcbe73e..5dd5634288970 100644 --- a/src/test/ui/span/macro-span-replacement.stderr +++ b/src/test/ui/span/macro-span-replacement.stderr @@ -1,8 +1,8 @@ warning: struct `S` is never constructed - --> $DIR/macro-span-replacement.rs:7:14 + --> $DIR/macro-span-replacement.rs:7:12 | LL | $b $a; - | ^ + | ^^ ... LL | m!(S struct); | ------------ in this macro invocation diff --git a/src/test/ui/span/method-and-field-eager-resolution.stderr b/src/test/ui/span/method-and-field-eager-resolution.stderr index 2dd650f38ce39..7d240589a3f13 100644 --- a/src/test/ui/span/method-and-field-eager-resolution.stderr +++ b/src/test/ui/span/method-and-field-eager-resolution.stderr @@ -3,8 +3,10 @@ error[E0282]: type annotations needed | LL | let mut x = Default::default(); | ^^^^^ +LL | +LL | x.0; + | - type must be known at this point | - = note: type must be known at this point help: consider giving `x` an explicit type | LL | let mut x: _ = Default::default(); @@ -15,8 +17,10 @@ error[E0282]: type annotations needed | LL | let mut x = Default::default(); | ^^^^^ +LL | +LL | x[0]; + | - type must be known at this point | - = note: type must be known at this point help: consider giving `x` an explicit type | LL | let mut x: _ = Default::default(); diff --git a/src/test/ui/span/move-closure.stderr b/src/test/ui/span/move-closure.stderr index 3e7041f02b388..dcc6078969449 100644 --- a/src/test/ui/span/move-closure.stderr +++ b/src/test/ui/span/move-closure.stderr @@ -7,7 +7,7 @@ LL | let x: () = move || (); | expected due to this | = note: expected unit type `()` - found closure `[closure@$DIR/move-closure.rs:5:17: 5:27]` + found closure `[closure@$DIR/move-closure.rs:5:17: 5:24]` help: use parentheses to call this closure | LL | let x: () = (move || ())(); diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index acfc60b51f330..79b13f45fd8ee 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -3,12 +3,10 @@ error[E0072]: recursive type `ListNode` has infinite size | LL | / struct LL | | ListNode -LL | | { -LL | | head: u8, -LL | | tail: Option<ListNode>, - | | ---------------- recursive without indirection -LL | | } - | |_^ recursive type has infinite size + | |________^ recursive type has infinite size +... +LL | tail: Option<ListNode>, + | ---------------- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable | diff --git a/src/test/ui/span/transitive-dep-span.stderr b/src/test/ui/span/transitive-dep-span.stderr index 2b3dfc5c13533..4dc3e57211605 100644 --- a/src/test/ui/span/transitive-dep-span.stderr +++ b/src/test/ui/span/transitive-dep-span.stderr @@ -1,19 +1,18 @@ error: expected one of `!` or `::`, found `error` --> $DIR/auxiliary/transitive_dep_three.rs:6:27 | -LL | / macro_rules! parse_error { -LL | | () => { parse error } - | | ^^^^^ expected one of `!` or `::` -LL | | } - | |_________- in this expansion of `transitive_dep_two::parse_error!` +LL | macro_rules! parse_error { + | ------------------------ in this expansion of `transitive_dep_two::parse_error!` +LL | () => { parse error } + | ^^^^^ expected one of `!` or `::` | ::: $DIR/transitive-dep-span.rs:13:1 | -LL | transitive_dep_two::parse_error!(); - | ---------------------------------- - | | - | in this macro invocation - | in this macro invocation +LL | transitive_dep_two::parse_error!(); + | ---------------------------------- + | | + | in this macro invocation + | in this macro invocation error: aborting due to previous error diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr index e4a8f7464626c..9dff6c64db46f 100644 --- a/src/test/ui/span/type-annotations-needed-expr.stderr +++ b/src/test/ui/span/type-annotations-needed-expr.stderr @@ -4,7 +4,6 @@ error[E0282]: type annotations needed LL | let _ = (vec![1,2,3]).into_iter().sum() as f64; | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum` | - = note: type must be known at this point help: consider specifying the generic argument | LL | let _ = (vec![1,2,3]).into_iter().sum::<S>() as f64; diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr index 3f1a5495e212f..360b7bc787a2e 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr @@ -11,67 +11,55 @@ LL | #![feature(specialization)] error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 | -LL | / impl<T> Foo for T { -LL | | fn foo(&self) {} -LL | | fn bar(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for T { + | ----------------- parent `impl` is here ... -LL | fn foo(&self) {} - | ^^^^^^^^^^^^^^^^ cannot specialize default item `foo` +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^^^^ cannot specialize default item `foo` | = note: to specialize, `foo` in the parent `impl` must be marked `default` error[E0520]: `bar` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:23:5 | -LL | / impl<T> Foo for T { -LL | | fn foo(&self) {} -LL | | fn bar(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for T { + | ----------------- parent `impl` is here ... -LL | fn bar(&self) {} - | ^^^^^^^^^^^^^^^^ cannot specialize default item `bar` +LL | fn bar(&self) {} + | ^^^^^^^^^^^^^^^^ cannot specialize default item `bar` | = note: to specialize, `bar` in the parent `impl` must be marked `default` error[E0520]: `T` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:37:5 | -LL | / impl<T> Bar for T { -LL | | type T = u8; -LL | | } - | |_- parent `impl` is here +LL | impl<T> Bar for T { + | ----------------- parent `impl` is here ... -LL | type T = (); - | ^^^^^^^^^^^^ cannot specialize default item `T` +LL | type T = (); + | ^^^^^^^^^^^^ cannot specialize default item `T` | = note: to specialize, `T` in the parent `impl` must be marked `default` error[E0520]: `baz` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:55:5 | -LL | / impl<T: Clone> Baz for T { -LL | | fn baz(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T: Clone> Baz for T { + | ------------------------ parent `impl` is here ... -LL | fn baz(&self) {} - | ^^^^^^^^^^^^^^^^ cannot specialize default item `baz` +LL | fn baz(&self) {} + | ^^^^^^^^^^^^^^^^ cannot specialize default item `baz` | = note: to specialize, `baz` in the parent `impl` must be marked `default` error[E0520]: `redundant` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:74:5 | -LL | / impl<T: Clone> Redundant for T { -LL | | fn redundant(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T: Clone> Redundant for T { + | ------------------------------ parent `impl` is here ... -LL | fn redundant(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `redundant` +LL | fn redundant(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `redundant` | = note: to specialize, `redundant` in the parent `impl` must be marked `default` diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 9894ecc64b518..d1004a6905887 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -12,27 +12,26 @@ error[E0599]: the method `foo_one` exists for struct `MyStruct`, but its trait b --> $DIR/specialization-trait-not-implemented.rs:22:29 | LL | struct MyStruct; - | ---------------- + | --------------- | | - | method `foo_one` not found for this + | method `foo_one` not found for this struct | doesn't satisfy `MyStruct: Foo` ... LL | println!("{}", MyStruct.foo_one()); | ^^^^^^^ method cannot be called on `MyStruct` due to unsatisfied trait bounds | note: trait bound `MyStruct: Foo` was not satisfied - --> $DIR/specialization-trait-not-implemented.rs:14:17 + --> $DIR/specialization-trait-not-implemented.rs:14:1 | LL | default impl<T> Foo for T { - | ^^^ ^ + | ^^^^^^^^^^^^^^^^---^^^^^- + | | + | unsatisfied trait bound introduced here note: the following trait must be implemented --> $DIR/specialization-trait-not-implemented.rs:7:1 | -LL | / trait Foo { -LL | | fn foo_one(&self) -> &'static str; -LL | | fn foo_two(&self) -> &'static str; -LL | | } - | |_^ +LL | trait Foo { + | ^^^^^^^^^ = help: items from traits can only be used if the trait is implemented and in scope note: `Foo` defines an item `foo_one`, perhaps you need to implement it --> $DIR/specialization-trait-not-implemented.rs:7:1 diff --git a/src/test/ui/specialization/issue-50452-fail.stderr b/src/test/ui/specialization/issue-50452-fail.stderr index 8e7c5037eff8f..7249ad73871c9 100644 --- a/src/test/ui/specialization/issue-50452-fail.stderr +++ b/src/test/ui/specialization/issue-50452-fail.stderr @@ -11,13 +11,11 @@ LL | #![feature(specialization)] error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/issue-50452-fail.rs:10:5 | -LL | fn foo() {} - | ^^^^^^^^^^^ cannot specialize default item `foo` +LL | fn foo() {} + | ^^^^^^^^^^^ cannot specialize default item `foo` ... -LL | / impl<T> Foo for T { -LL | | fn foo() {} -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for T { + | ----------------- parent `impl` is here | = note: to specialize, `foo` in the parent `impl` must be marked `default` diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index 8732b10d8f803..6d24997a5bf52 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -11,15 +11,11 @@ LL | #![feature(specialization)] error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()` --> $DIR/issue-52050.rs:28:1 | -LL | / impl<I> IntoPyDictPointer for I -LL | | where -LL | | I: Iterator, -LL | | { -LL | | } - | |_- first implementation here -LL | -LL | impl IntoPyDictPointer for () - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` +LL | impl<I> IntoPyDictPointer for I + | ------------------------------- first implementation here +... +LL | impl IntoPyDictPointer for () + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` | = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions diff --git a/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr b/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr index 6345cee2c3781..db5558f16be08 100644 --- a/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr +++ b/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr @@ -1,20 +1,14 @@ error: specializing impl repeats parameter `T` --> $DIR/dyn-trait-assoc-types.rs:22:1 | -LL | / impl<'a, T> Specializable for dyn B<T, Y = T> + 'a { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<'a, T> Specializable for dyn B<T, Y = T> + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specializing impl repeats parameter `T` --> $DIR/dyn-trait-assoc-types.rs:27:1 | -LL | / impl<'a, T> Specializable for dyn C<Y = (T, T)> + 'a { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<'a, T> Specializable for dyn C<Y = (T, T)> + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/specialization/min_specialization/issue-79224.rs b/src/test/ui/specialization/min_specialization/issue-79224.rs new file mode 100644 index 0000000000000..408732fe944fe --- /dev/null +++ b/src/test/ui/specialization/min_specialization/issue-79224.rs @@ -0,0 +1,24 @@ +#![feature(min_specialization)] +use std::fmt::{self, Display}; + +pub enum Cow<'a, B: ?Sized + 'a, O = <B as ToOwned>::Owned> +where + B: ToOwned, +{ + Borrowed(&'a B), + Owned(O), +} + +impl ToString for Cow<'_, str> { + fn to_string(&self) -> String { + String::new() + } +} + +impl<B: ?Sized> Display for Cow<'_, B> { //~ ERROR: the trait bound `B: Clone` is not satisfied [E0277] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { //~ ERROR: the trait bound `B: Clone` is not satisfied [E0277] + write!(f, "foo") + } +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/issue-79224.stderr b/src/test/ui/specialization/min_specialization/issue-79224.stderr new file mode 100644 index 0000000000000..cfb9007c7a28c --- /dev/null +++ b/src/test/ui/specialization/min_specialization/issue-79224.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `B: Clone` is not satisfied + --> $DIR/issue-79224.rs:18:17 + | +LL | impl<B: ?Sized> Display for Cow<'_, B> { + | ^^^^^^^ the trait `Clone` is not implemented for `B` + | + = note: required because of the requirements on the impl of `ToOwned` for `B` +help: consider further restricting this bound + | +LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> { + | +++++++++++++++++++ + +error[E0277]: the trait bound `B: Clone` is not satisfied + --> $DIR/issue-79224.rs:19:12 + | +LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + | ^^^^^ the trait `Clone` is not implemented for `B` + | + = note: required because of the requirements on the impl of `ToOwned` for `B` +help: consider further restricting this bound + | +LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> { + | +++++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index 1a7eb82c95b3d..a751ba793472e 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,11 +1,8 @@ -error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[54ea]::Id::This) }, Ty((I,))), [])` - --> $DIR/repeated_projection_type.rs:19:1 +error: cannot specialize on associated type `<V as Id>::This == (I,)` + --> $DIR/repeated_projection_type.rs:19:15 | -LL | / impl<I, V: Id<This = (I,)>> X for V { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<I, V: Id<This = (I,)>> X for V { + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr b/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr index ce9309f70122b..16dccb10b4530 100644 --- a/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr +++ b/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr @@ -1,11 +1,8 @@ error: specializing impl repeats parameter `'a` --> $DIR/repeating_lifetimes.rs:14:1 | -LL | / impl<'a> X for (&'a u8, &'a u8) { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<'a> X for (&'a u8, &'a u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/repeating_param.stderr b/src/test/ui/specialization/min_specialization/repeating_param.stderr index 8b4be1c499537..5e6adf723b54e 100644 --- a/src/test/ui/specialization/min_specialization/repeating_param.stderr +++ b/src/test/ui/specialization/min_specialization/repeating_param.stderr @@ -1,11 +1,8 @@ error: specializing impl repeats parameter `T` --> $DIR/repeating_param.rs:12:1 | -LL | / impl<T> X for (T, T) { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<T> X for (T, T) { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr index 964109dd10f47..ba9d6bbe30011 100644 --- a/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr +++ b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr @@ -1,13 +1,8 @@ error: cannot specialize on trait `HasMethod` - --> $DIR/spec-marker-supertraits.rs:22:1 + --> $DIR/spec-marker-supertraits.rs:22:9 | -LL | / impl<T: Marker> Spec for T { -LL | | -LL | | fn spec_me(&self) { -LL | | self.method(); -LL | | } -LL | | } - | |_^ +LL | impl<T: Marker> Spec for T { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/specialization_marker.stderr b/src/test/ui/specialization/min_specialization/specialization_marker.stderr index ffeced198211f..b47c14f3c9fd1 100644 --- a/src/test/ui/specialization/min_specialization/specialization_marker.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_marker.stderr @@ -8,7 +8,7 @@ error[E0714]: marker traits cannot have associated items --> $DIR/specialization_marker.rs:13:5 | LL | type X; - | ^^^^^^^ + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr index 5782ad01b39f6..e935786624b4b 100644 --- a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr @@ -1,11 +1,8 @@ error: cannot specialize on trait `Default` - --> $DIR/specialization_super_trait.rs:13:1 + --> $DIR/specialization_super_trait.rs:13:9 | -LL | / impl<T: Default> SpecMarker for T { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<T: Default> SpecMarker for T { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/specialization_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_trait.stderr index 8a70d6cc1bf21..bc87ae0f8b847 100644 --- a/src/test/ui/specialization/min_specialization/specialization_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_trait.stderr @@ -1,29 +1,20 @@ error: cannot specialize on `'static` lifetime --> $DIR/specialization_trait.rs:11:1 | -LL | / impl SpecMarker for &'static u8 { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl SpecMarker for &'static u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specializing impl repeats parameter `T` --> $DIR/specialization_trait.rs:16:1 | -LL | / impl<T> SpecMarker for (T, T) { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<T> SpecMarker for (T, T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot specialize on trait `Clone` - --> $DIR/specialization_trait.rs:21:1 + --> $DIR/specialization_trait.rs:21:9 | -LL | / impl<T: Clone> SpecMarker for [T] { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<T: Clone> SpecMarker for [T] { + | ^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/specialization/min_specialization/specialize_on_static.stderr b/src/test/ui/specialization/min_specialization/specialize_on_static.stderr index d1809d6dfbb52..9a16798f15cd1 100644 --- a/src/test/ui/specialization/min_specialization/specialize_on_static.stderr +++ b/src/test/ui/specialization/min_specialization/specialize_on_static.stderr @@ -1,11 +1,8 @@ error: cannot specialize on `'static` lifetime --> $DIR/specialize_on_static.rs:13:1 | -LL | / impl X for &'static u8 { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl X for &'static u8 { + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr b/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr index 35445fd09b949..7b79c7eb4ad1c 100644 --- a/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr @@ -1,11 +1,8 @@ error: cannot specialize on trait `SpecMarker` - --> $DIR/specialize_on_trait.rs:15:1 + --> $DIR/specialize_on_trait.rs:15:9 | -LL | / impl<T: SpecMarker> X for T { -LL | | -LL | | fn f() {} -LL | | } - | |_^ +LL | impl<T: SpecMarker> X for T { + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/non-defaulted-item-fail.stderr b/src/test/ui/specialization/non-defaulted-item-fail.stderr index 85ccbd809b02d..8b7d6797275bb 100644 --- a/src/test/ui/specialization/non-defaulted-item-fail.stderr +++ b/src/test/ui/specialization/non-defaulted-item-fail.stderr @@ -11,45 +11,33 @@ LL | #![feature(specialization, associated_type_defaults)] error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/non-defaulted-item-fail.rs:30:5 | -LL | / impl<T> Foo for Box<T> { -LL | | type Ty = bool; -LL | | const CONST: u8 = 0; -LL | | fn foo(&self) -> bool { false } -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for Box<T> { + | ---------------------- parent `impl` is here ... -LL | type Ty = Vec<()>; - | ^^^^^^^^^^^^^^^^^^ cannot specialize default item `Ty` +LL | type Ty = Vec<()>; + | ^^^^^^^^^^^^^^^^^^ cannot specialize default item `Ty` | = note: to specialize, `Ty` in the parent `impl` must be marked `default` error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/non-defaulted-item-fail.rs:32:5 | -LL | / impl<T> Foo for Box<T> { -LL | | type Ty = bool; -LL | | const CONST: u8 = 0; -LL | | fn foo(&self) -> bool { false } -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for Box<T> { + | ---------------------- parent `impl` is here ... -LL | const CONST: u8 = 42; - | ^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `CONST` +LL | const CONST: u8 = 42; + | ^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `CONST` | = note: to specialize, `CONST` in the parent `impl` must be marked `default` error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/non-defaulted-item-fail.rs:34:5 | -LL | / impl<T> Foo for Box<T> { -LL | | type Ty = bool; -LL | | const CONST: u8 = 0; -LL | | fn foo(&self) -> bool { false } -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for Box<T> { + | ---------------------- parent `impl` is here ... -LL | fn foo(&self) -> bool { true } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` +LL | fn foo(&self) -> bool { true } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` | = note: to specialize, `foo` in the parent `impl` must be marked `default` @@ -57,7 +45,7 @@ error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is no --> $DIR/non-defaulted-item-fail.rs:46:5 | LL | impl<T> Foo for Vec<T> {} - | ------------------------- parent `impl` is here + | ---------------------- parent `impl` is here ... LL | type Ty = Vec<()>; | ^^^^^^^^^^^^^^^^^^ cannot specialize default item `Ty` @@ -68,7 +56,7 @@ error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is --> $DIR/non-defaulted-item-fail.rs:48:5 | LL | impl<T> Foo for Vec<T> {} - | ------------------------- parent `impl` is here + | ---------------------- parent `impl` is here ... LL | const CONST: u8 = 42; | ^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `CONST` @@ -79,7 +67,7 @@ error[E0520]: `foo` specializes an item from a parent `impl`, but that item is n --> $DIR/non-defaulted-item-fail.rs:50:5 | LL | impl<T> Foo for Vec<T> {} - | ------------------------- parent `impl` is here + | ---------------------- parent `impl` is here ... LL | fn foo(&self) -> bool { true } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` diff --git a/src/test/ui/specialization/specialization-no-default.stderr b/src/test/ui/specialization/specialization-no-default.stderr index 711c1fda1499d..28c869a70559b 100644 --- a/src/test/ui/specialization/specialization-no-default.stderr +++ b/src/test/ui/specialization/specialization-no-default.stderr @@ -11,67 +11,55 @@ LL | #![feature(specialization)] error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 | -LL | / impl<T> Foo for T { -LL | | fn foo(&self) {} -LL | | fn bar(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for T { + | ----------------- parent `impl` is here ... -LL | fn foo(&self) {} - | ^^^^^^^^^^^^^^^^ cannot specialize default item `foo` +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^^^^ cannot specialize default item `foo` | = note: to specialize, `foo` in the parent `impl` must be marked `default` error[E0520]: `bar` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:23:5 | -LL | / impl<T> Foo for T { -LL | | fn foo(&self) {} -LL | | fn bar(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T> Foo for T { + | ----------------- parent `impl` is here ... -LL | fn bar(&self) {} - | ^^^^^^^^^^^^^^^^ cannot specialize default item `bar` +LL | fn bar(&self) {} + | ^^^^^^^^^^^^^^^^ cannot specialize default item `bar` | = note: to specialize, `bar` in the parent `impl` must be marked `default` error[E0520]: `T` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:37:5 | -LL | / impl<T> Bar for T { -LL | | type T = u8; -LL | | } - | |_- parent `impl` is here +LL | impl<T> Bar for T { + | ----------------- parent `impl` is here ... -LL | type T = (); - | ^^^^^^^^^^^^ cannot specialize default item `T` +LL | type T = (); + | ^^^^^^^^^^^^ cannot specialize default item `T` | = note: to specialize, `T` in the parent `impl` must be marked `default` error[E0520]: `baz` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:55:5 | -LL | / impl<T: Clone> Baz for T { -LL | | fn baz(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T: Clone> Baz for T { + | ------------------------ parent `impl` is here ... -LL | fn baz(&self) {} - | ^^^^^^^^^^^^^^^^ cannot specialize default item `baz` +LL | fn baz(&self) {} + | ^^^^^^^^^^^^^^^^ cannot specialize default item `baz` | = note: to specialize, `baz` in the parent `impl` must be marked `default` error[E0520]: `redundant` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:74:5 | -LL | / impl<T: Clone> Redundant for T { -LL | | fn redundant(&self) {} -LL | | } - | |_- parent `impl` is here +LL | impl<T: Clone> Redundant for T { + | ------------------------------ parent `impl` is here ... -LL | default fn redundant(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `redundant` +LL | default fn redundant(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `redundant` | = note: to specialize, `redundant` in the parent `impl` must be marked `default` diff --git a/src/test/ui/stability-attribute/accidental-stable-in-unstable.rs b/src/test/ui/stability-attribute/accidental-stable-in-unstable.rs new file mode 100644 index 0000000000000..f8bbe90cfc53b --- /dev/null +++ b/src/test/ui/stability-attribute/accidental-stable-in-unstable.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] +extern crate core; + +// Known accidental stabilizations with no known users, slated for un-stabilization +// fully stable @ core::char::UNICODE_VERSION +use core::unicode::UNICODE_VERSION; //~ ERROR use of unstable library feature 'unicode_internals' + +// Known accidental stabilizations with known users +// fully stable @ core::mem::transmute +use core::intrinsics::transmute; // depended upon by rand_core diff --git a/src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr b/src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr new file mode 100644 index 0000000000000..ff733822cab98 --- /dev/null +++ b/src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'unicode_internals' + --> $DIR/accidental-stable-in-unstable.rs:6:5 + | +LL | use core::unicode::UNICODE_VERSION; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unicode_internals)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/allowed-through-unstable.rs b/src/test/ui/stability-attribute/allowed-through-unstable.rs new file mode 100644 index 0000000000000..ff0228e4da6a8 --- /dev/null +++ b/src/test/ui/stability-attribute/allowed-through-unstable.rs @@ -0,0 +1,9 @@ +// Test for new `#[rustc_allowed_through_unstable_modules]` attribute +// +// aux-build:allowed-through-unstable-core.rs +#![crate_type = "lib"] + +extern crate allowed_through_unstable_core; + +use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; +use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature 'unstable_test_feature' diff --git a/src/test/ui/stability-attribute/allowed-through-unstable.stderr b/src/test/ui/stability-attribute/allowed-through-unstable.stderr new file mode 100644 index 0000000000000..132c00b89b229 --- /dev/null +++ b/src/test/ui/stability-attribute/allowed-through-unstable.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/allowed-through-unstable.rs:9:5 + | +LL | use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs b/src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs new file mode 100644 index 0000000000000..b597009a309c9 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs @@ -0,0 +1,14 @@ +#![crate_type = "lib"] +#![feature(staged_api)] +#![feature(rustc_attrs)] +#![stable(feature = "stable_test_feature", since = "1.2.0")] + +#[unstable(feature = "unstable_test_feature", issue = "1")] +pub mod unstable_module { + #[stable(feature = "stable_test_feature", since = "1.2.0")] + #[rustc_allowed_through_unstable_modules] + pub trait OldStableTraitAllowedThoughUnstable {} + + #[stable(feature = "stable_test_feature", since = "1.2.0")] + pub trait NewStableTraitNotAllowedThroughUnstable {} +} diff --git a/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs new file mode 100644 index 0000000000000..e45b00f994af4 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs @@ -0,0 +1,8 @@ +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.2.0")] + +#[unstable(feature = "unstable_test_feature", issue = "1")] +pub mod new_unstable_module { + #[stable(feature = "stable_test_feature", since = "1.2.0")] + pub trait OldTrait {} +} diff --git a/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs new file mode 100644 index 0000000000000..28ad8c28da158 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs @@ -0,0 +1,11 @@ +#![feature(staged_api)] +#![feature(unstable_test_feature)] +#![stable(feature = "stable_test_feature", since = "1.2.0")] + +extern crate stable_in_unstable_core; + +#[stable(feature = "stable_test_feature", since = "1.2.0")] +pub mod old_stable_module { + #[stable(feature = "stable_test_feature", since = "1.2.0")] + pub use stable_in_unstable_core::new_unstable_module::OldTrait; +} diff --git a/src/test/ui/stability-attribute/issue-99286-stable-intrinsics.rs b/src/test/ui/stability-attribute/issue-99286-stable-intrinsics.rs new file mode 100644 index 0000000000000..b9eee99226618 --- /dev/null +++ b/src/test/ui/stability-attribute/issue-99286-stable-intrinsics.rs @@ -0,0 +1,17 @@ +// check-pass +// +// Regression test for issue #99286 +// Tests that stabilized intrinsics are accessible +// through 'std::intrinsics', even though the module +// is unstable. + +#![allow(unused_imports)] +#![allow(deprecated)] + +use std::intrinsics::drop_in_place as _; +use std::intrinsics::copy_nonoverlapping as _; +use std::intrinsics::copy as _; +use std::intrinsics::write_bytes as _; +use std::intrinsics::{drop_in_place, copy_nonoverlapping, copy, write_bytes}; + +fn main() {} diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr index 6f2ade0d0abf4..10978728fa365 100644 --- a/src/test/ui/stability-attribute/missing-const-stability.stderr +++ b/src/test/ui/stability-attribute/missing-const-stability.stderr @@ -4,12 +4,6 @@ error: function has missing const stability attribute LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: associated function has missing const stability attribute - --> $DIR/missing-const-stability.rs:15:5 - | -LL | pub const fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^ - error: implementation has missing const stability attribute --> $DIR/missing-const-stability.rs:27:1 | @@ -19,5 +13,11 @@ LL | | fn fun() {} LL | | } | |_^ +error: associated function has missing const stability attribute + --> $DIR/missing-const-stability.rs:15:5 + | +LL | pub const fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 3 previous errors diff --git a/src/test/ui/stability-attribute/stable-in-unstable.rs b/src/test/ui/stability-attribute/stable-in-unstable.rs new file mode 100644 index 0000000000000..272a1a972340c --- /dev/null +++ b/src/test/ui/stability-attribute/stable-in-unstable.rs @@ -0,0 +1,46 @@ +// This test is meant to test that we can have a stable item in an unstable module, and that +// calling that item through the unstable module is unstable, but that re-exporting it from another +// crate in a stable module is fine. +// +// This is necessary to support moving items from `std` into `core` or `alloc` unstably while still +// exporting the original stable interface in `std`, such as moving `Error` into `core`. +// +// aux-build:stable-in-unstable-core.rs +// aux-build:stable-in-unstable-std.rs +#![crate_type = "lib"] + +extern crate stable_in_unstable_core; +extern crate stable_in_unstable_std; + +mod isolated1 { + use stable_in_unstable_core::new_unstable_module; //~ ERROR use of unstable library feature 'unstable_test_feature' + use stable_in_unstable_core::new_unstable_module::OldTrait; //~ ERROR use of unstable library feature 'unstable_test_feature' +} + +mod isolated2 { + use stable_in_unstable_std::old_stable_module::OldTrait; + + struct LocalType; + + impl OldTrait for LocalType {} +} + +mod isolated3 { + use stable_in_unstable_core::new_unstable_module::OldTrait; //~ ERROR use of unstable library feature 'unstable_test_feature' + + struct LocalType; + + impl OldTrait for LocalType {} +} + +mod isolated4 { + struct LocalType; + + impl stable_in_unstable_core::new_unstable_module::OldTrait for LocalType {} //~ ERROR use of unstable library feature 'unstable_test_feature' +} + +mod isolated5 { + struct LocalType; + + impl stable_in_unstable_std::old_stable_module::OldTrait for LocalType {} +} diff --git a/src/test/ui/stability-attribute/stable-in-unstable.stderr b/src/test/ui/stability-attribute/stable-in-unstable.stderr new file mode 100644 index 0000000000000..e123d83584c81 --- /dev/null +++ b/src/test/ui/stability-attribute/stable-in-unstable.stderr @@ -0,0 +1,39 @@ +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/stable-in-unstable.rs:16:9 + | +LL | use stable_in_unstable_core::new_unstable_module; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/stable-in-unstable.rs:17:9 + | +LL | use stable_in_unstable_core::new_unstable_module::OldTrait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/stable-in-unstable.rs:29:9 + | +LL | use stable_in_unstable_core::new_unstable_module::OldTrait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_test_feature' + --> $DIR/stable-in-unstable.rs:39:10 + | +LL | impl stable_in_unstable_core::new_unstable_module::OldTrait for LocalType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information + = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/static/static-priv-by-default2.stderr b/src/test/ui/static/static-priv-by-default2.stderr index d731da79246ee..b14e096d62a02 100644 --- a/src/test/ui/static/static-priv-by-default2.stderr +++ b/src/test/ui/static/static-priv-by-default2.stderr @@ -20,7 +20,7 @@ note: the static `private` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:3:1 | LL | static private: isize = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/statics/uninhabited-static.stderr b/src/test/ui/statics/uninhabited-static.stderr index 855e5dca92a7c..88ee4cbdc2efc 100644 --- a/src/test/ui/statics/uninhabited-static.stderr +++ b/src/test/ui/statics/uninhabited-static.stderr @@ -2,7 +2,7 @@ error: static of uninhabited type --> $DIR/uninhabited-static.rs:6:5 | LL | static VOID: Void; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/uninhabited-static.rs:2:9 @@ -17,7 +17,7 @@ error: static of uninhabited type --> $DIR/uninhabited-static.rs:8:5 | LL | static NEVER: !; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840> @@ -27,7 +27,7 @@ error: static of uninhabited type --> $DIR/uninhabited-static.rs:12:1 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840> @@ -37,7 +37,7 @@ error: static of uninhabited type --> $DIR/uninhabited-static.rs:16:1 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840> diff --git a/src/test/ui/std-backtrace.rs b/src/test/ui/std-backtrace.rs index b5e76666af1f8..07de066b55863 100644 --- a/src/test/ui/std-backtrace.rs +++ b/src/test/ui/std-backtrace.rs @@ -5,6 +5,7 @@ // ignore-sgx no processes // ignore-msvc see #62897 and `backtrace-debuginfo.rs` test // compile-flags:-g +// compile-flags:-Cstrip=none #![feature(backtrace)] diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr index 40b4b42f74293..b77c8c7fd5bcc 100644 --- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -1,3 +1,29 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9 + | +LL | struct Struct5<T: ?Sized>{ + | - this type parameter needs to be `std::marker::Sized` +LL | _t: X<T>, + | ^^^^ doesn't have a size known at compile-time + | +note: required by a bound in `X` + --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 + | +LL | struct X<T>(T); + | ^ required by this bound in `X` +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 + | +LL | struct X<T>(T); + | ^ - ...if indirection were used here: `Box<T>` + | | + | this could be changed to `T: ?Sized`... +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - struct Struct5<T: ?Sized>{ +LL + struct Struct5<T>{ + | + error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/adt-param-with-implicit-sized-bound.rs:2:19 | @@ -81,32 +107,6 @@ help: consider relaxing the implicit `Sized` restriction LL | struct Struct4<T: ?Sized>{ | ++++++++ -error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9 - | -LL | struct Struct5<T: ?Sized>{ - | - this type parameter needs to be `std::marker::Sized` -LL | _t: X<T>, - | ^^^^ doesn't have a size known at compile-time - | -note: required by a bound in `X` - --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 - | -LL | struct X<T>(T); - | ^ required by this bound in `X` -help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` - --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 - | -LL | struct X<T>(T); - | ^ - ...if indirection were used here: `Box<T>` - | | - | this could be changed to `T: ?Sized`... -help: consider removing the `?Sized` bound to make the type parameter `Sized` - | -LL - struct Struct5<T: ?Sized>{ -LL + struct Struct5<T>{ - | - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr index 3d367eca707f4..805c75f464cd5 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:6:34 | LL | let _: Option<(i32, bool)> = Some(1, 2); - | ^^^^ - - argument unexpected + | ^^^^ - - argument of type `{integer}` unexpected | | | expected tuple, found integer | @@ -22,7 +22,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:8:5 | LL | int_bool(1, 2); - | ^^^^^^^^ - - argument unexpected + | ^^^^^^^^ - - argument of type `{integer}` unexpected | | | expected tuple, found integer | diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index f6d158782dad2..2448a5149654d 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -9,7 +9,7 @@ note: tuple variant defined here | LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), | ^^ -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | let _: Result<(i32, i8), ()> = Ok((1, 2)); | + + @@ -25,7 +25,7 @@ note: tuple variant defined here | LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), | ^^^^ -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); | + + @@ -97,7 +97,7 @@ note: function defined here | LL | fn two_ints(_: (i32, i32)) { | ^^^^^^^^ ------------- -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | two_ints((1, 2)); | + + @@ -113,7 +113,7 @@ note: function defined here | LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) { | ^^^^^^^^^^^^ ---------------- -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | with_generic((3, 4)); | + + @@ -129,7 +129,7 @@ note: function defined here | LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) { | ^^^^^^^^^^^^ ---------------- -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | with_generic((a, b)); | + + diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 766db2a8356e7..c7d420e0aae83 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -21,18 +21,18 @@ help: use parentheses to call the function LL | bar(foo()); | ++ -error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future +error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9 | LL | let async_closure = async || (); | -------- consider calling this closure LL | bar(async_closure); - | --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future + | --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future | | | required by a bound introduced by this call | - = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` - = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36] must be a future or must implement `IntoFuture` to be awaited + = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` + = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33] must be a future or must implement `IntoFuture` to be awaited note: required by a bound in `bar` --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16 | diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr index d6163a5a7cfe3..54122cb7360b4 100644 --- a/src/test/ui/suggestions/attribute-typos.stderr +++ b/src/test/ui/suggestions/attribute-typos.stderr @@ -19,7 +19,7 @@ LL | #[tests] ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | pub macro test($item:item) { - | -------------------------- similarly named attribute macro `test` defined here + | -------------- similarly named attribute macro `test` defined here error: cannot find attribute `deprcated` in this scope --> $DIR/attribute-typos.rs:1:3 diff --git a/src/test/ui/suggestions/auxiliary/meow.rs b/src/test/ui/suggestions/auxiliary/meow.rs new file mode 100644 index 0000000000000..115df70a69060 --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/meow.rs @@ -0,0 +1,11 @@ +pub trait Meow { + fn meow(&self) {} +} + +pub struct GlobalMeow; + +impl Meow for GlobalMeow {} + +pub(crate) struct PrivateMeow; + +impl Meow for PrivateMeow {} diff --git a/src/test/ui/suggestions/auxiliary/not-object-safe.rs b/src/test/ui/suggestions/auxiliary/not-object-safe.rs new file mode 100644 index 0000000000000..7c9829b823ede --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/not-object-safe.rs @@ -0,0 +1,6 @@ +use std::sync::Arc; + +pub trait A { + fn f(); + fn f2(self: &Arc<Self>); +} diff --git a/src/test/ui/suggestions/const-in-struct-pat.stderr b/src/test/ui/suggestions/const-in-struct-pat.stderr index 784f1bdb6cf3d..c8b93f3dc48f4 100644 --- a/src/test/ui/suggestions/const-in-struct-pat.stderr +++ b/src/test/ui/suggestions/const-in-struct-pat.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/const-in-struct-pat.rs:8:17 | LL | struct foo; - | ----------- unit struct defined here + | ---------- unit struct defined here ... LL | let Thing { foo } = t; | ^^^ - this expression has type `Thing` diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index af64c09d5cadb..618bcaca14c4d 100644 --- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -8,7 +8,7 @@ LL | let A = 3; | help: introduce a variable instead: `a_var` ... LL | const A: i32 = 2; - | ----------------- constant defined here + | ------------ constant defined here | = note: the matched value is of type `i32` diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr index 501d083e2bc60..4186dc7cb35ae 100644 --- a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr @@ -33,7 +33,7 @@ LL | impl<T: Debug + Trait> Debug for Inner<T> { | ^^^^^ ^^^^^^^^ = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Debug` for `&c::Inner<T>` - = note: required for the cast to the object type `dyn Debug` + = note: required for the cast from `&c::Inner<T>` to the object type `dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -55,7 +55,7 @@ LL | impl<T> Debug for Inner<T> where T: Debug, T: Trait { | ^^^^^ ^^^^^^^^ = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Debug` for `&d::Inner<T>` - = note: required for the cast to the object type `dyn Debug` + = note: required for the cast from `&d::Inner<T>` to the object type `dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -77,7 +77,7 @@ LL | impl<T> Debug for Inner<T> where T: Debug + Trait { | ^^^^^ ^^^^^^^^ = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Debug` for `&e::Inner<T>` - = note: required for the cast to the object type `dyn Debug` + = note: required for the cast from `&e::Inner<T>` to the object type `dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -99,7 +99,7 @@ LL | impl<T: Debug> Debug for Inner<T> where T: Trait { | ^^^^^ ^^^^^^^^ = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Debug` for `&f::Inner<T>` - = note: required for the cast to the object type `dyn Debug` + = note: required for the cast from `&f::Inner<T>` to the object type `dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | diff --git a/src/test/ui/suggestions/derive-trait-for-method-call.stderr b/src/test/ui/suggestions/derive-trait-for-method-call.stderr index 2af3ba1d5bb9c..7cc372f2422ae 100644 --- a/src/test/ui/suggestions/derive-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/derive-trait-for-method-call.stderr @@ -11,7 +11,7 @@ LL | enum CloneEnum { | -------------- doesn't satisfy `CloneEnum: Default` ... LL | struct Foo<X, Y> (X, Y); - | ------------------------ method `test` not found for this + | ---------------- method `test` not found for this struct ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo<Enum, CloneEnum>` due to unsatisfied trait bounds @@ -23,14 +23,8 @@ LL | let y = x.test(); note: the following trait must be implemented --> $SRC_DIR/core/src/default.rs:LL:COL | -LL | / pub trait Default: Sized { -LL | | /// Returns the "default value" for a type. -LL | | /// -LL | | /// Default values are often some kind of initial value, identity value, or anything else that -... | -LL | | fn default() -> Self; -LL | | } - | |_^ +LL | pub trait Default: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider annotating `Enum` with `#[derive(Clone)]` | LL | #[derive(Clone)] @@ -49,7 +43,7 @@ LL | struct CloneStruct { | ------------------ doesn't satisfy `CloneStruct: Default` ... LL | struct Foo<X, Y> (X, Y); - | ------------------------ method `test` not found for this + | ---------------- method `test` not found for this struct ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo<Struct, CloneStruct>` due to unsatisfied trait bounds @@ -71,7 +65,7 @@ error[E0599]: the method `test` exists for struct `Foo<Vec<Enum>, Instant>`, but --> $DIR/derive-trait-for-method-call.rs:40:15 | LL | struct Foo<X, Y> (X, Y); - | ------------------------ method `test` not found for this + | ---------------- method `test` not found for this struct ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo<Vec<Enum>, Instant>` due to unsatisfied trait bounds @@ -79,7 +73,7 @@ LL | let y = x.test(); ::: $SRC_DIR/std/src/time.rs:LL:COL | LL | pub struct Instant(time::Instant); - | ---------------------------------- doesn't satisfy `Instant: Default` + | ------------------ doesn't satisfy `Instant: Default` | ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL | diff --git a/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.rs b/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.rs new file mode 100644 index 0000000000000..acb897571d64e --- /dev/null +++ b/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.rs @@ -0,0 +1,15 @@ +// https://github.com/rust-lang/rust/issues/96834 +// +// This test case verifies that rustc does not make an unhelpful suggestion: +// +// help: consider wrapping the receiver expression with the appropriate type +// | +// 14 | Pin::new(&mut a).set(0, 3); +// | +++++++++++++ + +// +// We can tell that it isn't helpful, because `Pin::set` takes two parameters (including +// the receiver), but the function call on line 14 supplies three. +fn main() { + let mut a = [0u8; 1]; + a.set(0, 3); //~ERROR +} diff --git a/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr b/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr new file mode 100644 index 0000000000000..677aa031bf7d6 --- /dev/null +++ b/src/test/ui/suggestions/dont-suggest-pin-array-dot-set.stderr @@ -0,0 +1,9 @@ +error[E0599]: no method named `set` found for array `[u8; 1]` in the current scope + --> $DIR/dont-suggest-pin-array-dot-set.rs:14:7 + | +LL | a.set(0, 3); + | ^^^ help: there is an associated function with a similar name: `get` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr index fb1055c9c3093..e06ee4290abd8 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr @@ -1,487 +1,342 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:28:21 | -LL | let x = X(Y); - | - captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; - | | -- ^ help: consider borrowing here: `&x` - | | | - | | data moved here - | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -LL | | -LL | | -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let x = X(Y); + | - captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +LL | let X(_t) = x; + | -- ^ help: consider borrowing here: `&x` + | | + | data moved here + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:32:34 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -LL | | -LL | | if let Either::One(_t) = e { } - | | -- ^ help: consider borrowing here: `&e` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | if let Either::One(_t) = e { } + | -- ^ help: consider borrowing here: `&e` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:36:37 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | while let Either::One(_t) = e { } - | | -- ^ help: consider borrowing here: `&e` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | while let Either::One(_t) = e { } + | -- ^ help: consider borrowing here: `&e` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:40:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match e { - | | ^ help: consider borrowing here: `&e` -... | -LL | | Either::One(_t) - | | -- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | match e { + | ^ help: consider borrowing here: `&e` +... +LL | Either::One(_t) + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:47:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match e { - | | ^ help: consider borrowing here: `&e` -... | -LL | | Either::One(_t) => (), - | | -- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | match e { + | ^ help: consider borrowing here: `&e` +... +LL | Either::One(_t) => (), + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:56:25 | -LL | let x = X(Y); - | - captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | let X(mut _t) = x; - | | ------ ^ help: consider borrowing here: `&x` - | | | - | | data moved here - | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let x = X(Y); + | - captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | let X(mut _t) = x; + | ------ ^ help: consider borrowing here: `&x` + | | + | data moved here + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:60:38 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | if let Either::One(mut _t) = em { } - | | ------ ^^ help: consider borrowing here: `&em` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | if let Either::One(mut _t) = em { } + | ------ ^^ help: consider borrowing here: `&em` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:64:41 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | while let Either::One(mut _t) = em { } - | | ------ ^^ help: consider borrowing here: `&em` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | while let Either::One(mut _t) = em { } + | ------ ^^ help: consider borrowing here: `&em` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:68:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match em { - | | ^^ help: consider borrowing here: `&em` -... | -LL | | Either::One(mut _t) - | | ------ - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | match em { + | ^^ help: consider borrowing here: `&em` +... +LL | Either::One(mut _t) + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:75:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fn(|| { - | ________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match em { - | | ^^ help: consider borrowing here: `&em` -... | -LL | | Either::One(mut _t) => (), - | | ------ - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `Fn` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fn(|| { + | -- captured by this `Fn` closure +... +LL | match em { + | ^^ help: consider borrowing here: `&em` +... +LL | Either::One(mut _t) => (), + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:95:21 | -LL | let x = X(Y); - | - captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; - | | -- ^ help: consider borrowing here: `&x` - | | | - | | data moved here - | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -LL | | -LL | | -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let x = X(Y); + | - captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +LL | let X(_t) = x; + | -- ^ help: consider borrowing here: `&x` + | | + | data moved here + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:99:34 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -LL | | -LL | | if let Either::One(_t) = e { } - | | -- ^ help: consider borrowing here: `&e` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | if let Either::One(_t) = e { } + | -- ^ help: consider borrowing here: `&e` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:103:37 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | while let Either::One(_t) = e { } - | | -- ^ help: consider borrowing here: `&e` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | while let Either::One(_t) = e { } + | -- ^ help: consider borrowing here: `&e` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:107:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match e { - | | ^ help: consider borrowing here: `&e` -... | -LL | | Either::One(_t) - | | -- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | match e { + | ^ help: consider borrowing here: `&e` +... +LL | Either::One(_t) + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:114:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match e { - | | ^ help: consider borrowing here: `&e` -... | -LL | | Either::One(_t) => (), - | | -- - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let e = Either::One(X(Y)); + | - captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | match e { + | ^ help: consider borrowing here: `&e` +... +LL | Either::One(_t) => (), + | -- + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:123:25 | -LL | let x = X(Y); - | - captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | let X(mut _t) = x; - | | ------ ^ help: consider borrowing here: `&x` - | | | - | | data moved here - | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let x = X(Y); + | - captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | let X(mut _t) = x; + | ------ ^ help: consider borrowing here: `&x` + | | + | data moved here + | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:127:38 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | if let Either::One(mut _t) = em { } - | | ------ ^^ help: consider borrowing here: `&em` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | if let Either::One(mut _t) = em { } + | ------ ^^ help: consider borrowing here: `&em` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:131:41 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | while let Either::One(mut _t) = em { } - | | ------ ^^ help: consider borrowing here: `&em` - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | while let Either::One(mut _t) = em { } + | ------ ^^ help: consider borrowing here: `&em` + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:135:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match em { - | | ^^ help: consider borrowing here: `&em` -... | -LL | | Either::One(mut _t) - | | ------ - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | match em { + | ^^ help: consider borrowing here: `&em` +... +LL | Either::One(mut _t) + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:142:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match em { - | | ^^ help: consider borrowing here: `&em` -... | -LL | | Either::One(mut _t) => (), - | | ------ - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | match em { + | ^^ help: consider borrowing here: `&em` +... +LL | Either::One(mut _t) => (), + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:150:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable -... -LL | consume_fnmut(|| { - | ___________________- -LL | | let X(_t) = x; -LL | | -LL | | -... | -LL | | match em { - | | ^^ help: consider borrowing here: `&em` -... | -LL | | Either::One(mut _t) => (), - | | ------ - | | | - | | data moved here - | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -... | -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable +... +LL | consume_fnmut(|| { + | -- captured by this `FnMut` closure +... +LL | match em { + | ^^ help: consider borrowing here: `&em` +... +LL | Either::One(mut _t) => (), + | ------ + | | + | data moved here + | move occurs because `_t` has type `X`, which does not implement the `Copy` trait error: aborting due to 21 previous errors diff --git a/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr b/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr index 8fcadbf4c75f4..4658ecb3a7a95 100644 --- a/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr +++ b/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `pick` found for struct `Chaenomeles` in the curre --> $DIR/dont-wrap-ambiguous-receivers.rs:18:25 | LL | pub struct Chaenomeles; - | ----------------------- method `pick` not found for this + | ---------------------- method `pick` not found for this struct ... LL | banana::Chaenomeles.pick() | ^^^^ method not found in `Chaenomeles` diff --git a/src/test/ui/suggestions/field-has-method.stderr b/src/test/ui/suggestions/field-has-method.stderr index 3a57436f200ba..def16401750d5 100644 --- a/src/test/ui/suggestions/field-has-method.stderr +++ b/src/test/ui/suggestions/field-has-method.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `kind` found for struct `InferOk` in the current s --> $DIR/field-has-method.rs:19:15 | LL | struct InferOk<T> { - | ----------------- method `kind` not found for this + | ----------------- method `kind` not found for this struct ... LL | let k = i.kind(); | ^^^^ method not found in `InferOk<Ty>` diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 101e7aecc0226..fb0a6f70bfb46 100644 --- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -19,13 +19,13 @@ help: use parentheses to call the function LL | bar(foo()); | ++ -error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]: T` is not satisfied +error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]: T` is not satisfied --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:19:9 | LL | let closure = || S; | -- consider calling this closure LL | bar(closure); - | --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]` + | --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]` | | | required by a bound introduced by this call | diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 25ce458f6d813..e75ce0da82e51 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -40,7 +40,7 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:30:16 | LL | struct S(usize, usize); - | ----------------------- fn(usize, usize) -> S {S} defined here + | -------- fn(usize, usize) -> S {S} defined here ... LL | let _: S = S; | - ^ expected struct `S`, found fn item @@ -76,7 +76,7 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:32:16 | LL | struct V(); - | ----------- fn() -> V {V} defined here + | -------- fn() -> V {V} defined here ... LL | let _: V = V; | - ^ expected struct `V`, found fn item @@ -130,7 +130,7 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:35:16 | LL | A(usize), - | -------- fn(usize) -> E {E::A} defined here + | - fn(usize) -> E {E::A} defined here ... LL | let _: E = E::A; | - ^^^^ expected enum `E`, found fn item @@ -278,14 +278,14 @@ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:46:20 | LL | let closure = || 42; - | ----- the found closure + | -- the found closure LL | let _: usize = closure; | ----- ^^^^^^^ expected `usize`, found closure | | | expected due to this | = note: expected type `usize` - found closure `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:24]` + found closure `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:21]` help: use parentheses to call this closure | LL | let _: usize = closure(); diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs new file mode 100644 index 0000000000000..fe291e021bc54 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -0,0 +1,21 @@ +// edition:2021 +// gate-test-anonymous_lifetime_in_impl_trait +// Verify the behaviour of `feature(anonymous_lifetime_in_impl_trait)`. + +fn f(_: impl Iterator<Item = &'_ ()>) {} +//~^ ERROR anonymous lifetimes in `impl Trait` are unstable + +fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } +//~^ ERROR anonymous lifetimes in `impl Trait` are unstable +//~| ERROR missing lifetime specifier + +// Anonymous lifetimes in async fn are already allowed. +// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`. +async fn h(_: impl Iterator<Item = &'_ ()>) {} + +// Anonymous lifetimes in async fn are already allowed. +// But that lifetime does not participate in resolution. +async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } +//~^ ERROR missing lifetime specifier + +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr new file mode 100644 index 0000000000000..9adc9679eee47 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -0,0 +1,44 @@ +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31 + | +LL | fn f(_: impl Iterator<Item = &'_ ()>) {} + | ^^ + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50 + | +LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() } + | ~~~~~~~ + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31 + | +LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } + | ^^ + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56 + | +LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() } + | ~~~~~~~ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0658. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs index 22dc448c97ff0..dcc716f56b705 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs @@ -1,2 +1,19 @@ -fn f(_: impl Iterator<Item = &'_ ()>) {} //~ ERROR missing lifetime specifier +// edition:2021 + +#![feature(anonymous_lifetime_in_impl_trait)] + +// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`. +fn f(_: impl Iterator<Item = &'_ ()>) {} + +// But that lifetime does not participate in resolution. +fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } +//~^ ERROR missing lifetime specifier + +// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`. +async fn h(_: impl Iterator<Item = &'_ ()>) {} + +// But that lifetime does not participate in resolution. +async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } +//~^ ERROR missing lifetime specifier + fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr index a3a339b13c478..d3c64cb466d74 100644 --- a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr +++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr @@ -1,14 +1,27 @@ error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime.rs:1:31 + --> $DIR/impl-trait-missing-lifetime.rs:9:50 | -LL | fn f(_: impl Iterator<Item = &'_ ()>) {} - | ^^ expected named lifetime parameter +LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter | -help: consider introducing a named lifetime parameter + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime | -LL | fn f<'a>(_: impl Iterator<Item = &'a ()>) {} - | ++++ ~~ +LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() } + | ~~~~~~~ -error: aborting due to previous error +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime.rs:16:56 + | +LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() } + | ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() } + | ~~~~~~~ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index 229c4b824f275..a763eb6f2f854 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -1,3 +1,22 @@ +error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:6:13 + | +LL | qux(constraint); + | --- ^^^^^^^^^^ `<impl Iterator as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by a bound introduced by this call + | + = help: the trait `Debug` is not implemented for `<impl Iterator as Iterator>::Item` +note: required by a bound in `qux` + --> $DIR/impl-trait-with-missing-bounds.rs:50:16 + | +LL | fn qux(_: impl std::fmt::Debug) {} + | ^^^^^^^^^^^^^^^ required by this bound in `qux` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn foo<I: Iterator>(constraints: I) where <I as Iterator>::Item: Debug { + | +++++++++++++ ~ ++++++++++++++++++++++++++++++++++ + error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:14:13 | @@ -74,25 +93,6 @@ help: introduce a type parameter with a trait bound instead of using `impl Trait LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as Iterator>::Item: Debug { | +++++++++++++++++++++++++++++++ ~ ++++++++++++++++++++++++++++++++++ -error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug` - --> $DIR/impl-trait-with-missing-bounds.rs:6:13 - | -LL | qux(constraint); - | --- ^^^^^^^^^^ `<impl Iterator as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | | - | required by a bound introduced by this call - | - = help: the trait `Debug` is not implemented for `<impl Iterator as Iterator>::Item` -note: required by a bound in `qux` - --> $DIR/impl-trait-with-missing-bounds.rs:50:16 - | -LL | fn qux(_: impl std::fmt::Debug) {} - | ^^^^^^^^^^^^^^^ required by this bound in `qux` -help: introduce a type parameter with a trait bound instead of using `impl Trait` - | -LL | fn foo<I: Iterator>(constraints: I) where <I as Iterator>::Item: Debug { - | +++++++++++++ ~ ++++++++++++++++++++++++++++++++++ - error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:45:13 | diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr index 8ec7b7bf49658..20f8e65f769a4 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr @@ -1,6 +1,8 @@ error[E0599]: no method named `hello` found for type parameter `impl Foo` in the current scope --> $DIR/impl-trait-with-missing-trait-bounds-in-arg.rs:15:9 | +LL | fn test(foo: impl Foo) { + | -------- method `hello` not found for this type parameter LL | foo.hello(); | ^^^^^ method not found in `impl Foo` | diff --git a/src/test/ui/suggestions/invalid-bin-op.stderr b/src/test/ui/suggestions/invalid-bin-op.stderr index 94bd2d4156582..08502dfeb2d59 100644 --- a/src/test/ui/suggestions/invalid-bin-op.stderr +++ b/src/test/ui/suggestions/invalid-bin-op.stderr @@ -10,7 +10,7 @@ note: an implementation of `PartialEq<_>` might be missing for `S<T>` --> $DIR/invalid-bin-op.rs:5:1 | LL | struct S<T>(T); - | ^^^^^^^^^^^^^^^ must implement `PartialEq<_>` + | ^^^^^^^^^^^ must implement `PartialEq<_>` help: consider annotating `S<T>` with `#[derive(PartialEq)]` | LL | #[derive(PartialEq)] diff --git a/src/test/ui/suggestions/issue-21673.stderr b/src/test/ui/suggestions/issue-21673.stderr index 0a4aaa61bc784..523d7a7ccd29c 100644 --- a/src/test/ui/suggestions/issue-21673.stderr +++ b/src/test/ui/suggestions/issue-21673.stderr @@ -13,6 +13,8 @@ LL | fn call_method<T: std::fmt::Debug + Foo>(x: &T) { error[E0599]: no method named `method` found for type parameter `T` in the current scope --> $DIR/issue-21673.rs:10:7 | +LL | fn call_method_2<T>(x: T) { + | - method `method` not found for this type parameter LL | x.method() | ^^^^^^ method not found in `T` | diff --git a/src/test/ui/suggestions/issue-52820.fixed b/src/test/ui/suggestions/issue-52820.fixed new file mode 100644 index 0000000000000..514690de4d045 --- /dev/null +++ b/src/test/ui/suggestions/issue-52820.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(dead_code)] + +struct Bravery { + guts: String, + brains: String, +} + +fn main() { + let guts = "mettle"; + let _ = Bravery { + guts: guts.to_string(), //~ ERROR mismatched types + brains: guts.to_string(), //~ ERROR mismatched types + }; +} diff --git a/src/test/ui/suggestions/issue-52820.rs b/src/test/ui/suggestions/issue-52820.rs index 075b07f565203..17cd9224c57ec 100644 --- a/src/test/ui/suggestions/issue-52820.rs +++ b/src/test/ui/suggestions/issue-52820.rs @@ -1,3 +1,6 @@ +// run-rustfix +#![allow(dead_code)] + struct Bravery { guts: String, brains: String, diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr index 7b46584450192..09269ed4eee99 100644 --- a/src/test/ui/suggestions/issue-52820.stderr +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-52820.rs:9:9 + --> $DIR/issue-52820.rs:12:9 | LL | guts, | ^^^^ expected struct `String`, found `&str` @@ -10,13 +10,13 @@ LL | guts: guts.to_string(), | +++++ ++++++++++++ error[E0308]: mismatched types - --> $DIR/issue-52820.rs:10:17 + --> $DIR/issue-52820.rs:13:17 | LL | brains: guts.clone(), - | ^^^^^^^^^^^^ - | | + | ^^^^^-----^^ + | | | + | | help: try using a conversion method: `to_string` | expected struct `String`, found `&str` - | help: try using a conversion method: `guts.to_string()` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-53692.fixed b/src/test/ui/suggestions/issue-53692.fixed new file mode 100644 index 0000000000000..35a677b476186 --- /dev/null +++ b/src/test/ui/suggestions/issue-53692.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused_variables)] + +fn main() { + let items = vec![1, 2, 3]; + let ref_items: &[i32] = &items; + let items_clone: Vec<i32> = ref_items.to_vec(); + //~^ ERROR mismatched types + + // in that case no suggestion will be triggered + let items_clone_2: Vec<i32> = items.clone(); + + let s = "hi"; + let string: String = s.to_string(); + //~^ ERROR mismatched types + + // in that case no suggestion will be triggered + let s2 = "hi"; + let string_2: String = s2.to_string(); +} diff --git a/src/test/ui/suggestions/issue-53692.rs b/src/test/ui/suggestions/issue-53692.rs index 30f344e428248..6f6707be5f651 100644 --- a/src/test/ui/suggestions/issue-53692.rs +++ b/src/test/ui/suggestions/issue-53692.rs @@ -1,17 +1,20 @@ +// run-rustfix +#![allow(unused_variables)] + fn main() { - let items = vec![1, 2, 3]; - let ref_items: &[i32] = &items; - let items_clone: Vec<i32> = ref_items.clone(); -//~^ ERROR mismatched types + let items = vec![1, 2, 3]; + let ref_items: &[i32] = &items; + let items_clone: Vec<i32> = ref_items.clone(); + //~^ ERROR mismatched types - // in that case no suggestion will be triggered - let items_clone_2:Vec<i32> = items.clone(); + // in that case no suggestion will be triggered + let items_clone_2: Vec<i32> = items.clone(); - let s = "hi"; - let string: String = s.clone(); -//~^ ERROR mismatched types + let s = "hi"; + let string: String = s.clone(); + //~^ ERROR mismatched types - // in that case no suggestion will be triggered - let s2 = "hi"; - let string_2: String = s2.to_string(); + // in that case no suggestion will be triggered + let s2 = "hi"; + let string_2: String = s2.to_string(); } diff --git a/src/test/ui/suggestions/issue-53692.stderr b/src/test/ui/suggestions/issue-53692.stderr index 09c78da54bcd0..3a1b624f402f0 100644 --- a/src/test/ui/suggestions/issue-53692.stderr +++ b/src/test/ui/suggestions/issue-53692.stderr @@ -1,25 +1,25 @@ error[E0308]: mismatched types - --> $DIR/issue-53692.rs:4:37 + --> $DIR/issue-53692.rs:7:33 | -LL | let items_clone: Vec<i32> = ref_items.clone(); - | -------- ^^^^^^^^^^^^^^^^^ - | | | - | | expected struct `Vec`, found `&[i32]` - | | help: try using a conversion method: `ref_items.to_vec()` - | expected due to this +LL | let items_clone: Vec<i32> = ref_items.clone(); + | -------- ^^^^^^^^^^-----^^ + | | | | + | | | help: try using a conversion method: `to_vec` + | | expected struct `Vec`, found `&[i32]` + | expected due to this | = note: expected struct `Vec<i32>` found reference `&[i32]` error[E0308]: mismatched types - --> $DIR/issue-53692.rs:11:30 + --> $DIR/issue-53692.rs:14:26 | -LL | let string: String = s.clone(); - | ------ ^^^^^^^^^ - | | | - | | expected struct `String`, found `&str` - | | help: try using a conversion method: `s.to_string()` - | expected due to this +LL | let string: String = s.clone(); + | ------ ^^-----^^ + | | | | + | | | help: try using a conversion method: `to_string` + | | expected struct `String`, found `&str` + | expected due to this error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-84973-blacklist.stderr b/src/test/ui/suggestions/issue-84973-blacklist.stderr index 5d8d688a073ca..ae0d3efca4727 100644 --- a/src/test/ui/suggestions/issue-84973-blacklist.stderr +++ b/src/test/ui/suggestions/issue-84973-blacklist.stderr @@ -30,11 +30,11 @@ help: consider annotating `S` with `#[derive(Clone)]` LL | #[derive(Clone)] | -error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` cannot be unpinned +error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:22]` cannot be unpinned --> $DIR/issue-84973-blacklist.rs:17:5 | LL | f_unpin(static || { yield; }); - | ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` + | ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:22]` | = note: consider using `Box::pin` note: required by a bound in `f_unpin` diff --git a/src/test/ui/suggestions/issue-97677.fixed b/src/test/ui/suggestions/issue-97677.fixed new file mode 100644 index 0000000000000..73ca9f97b43a3 --- /dev/null +++ b/src/test/ui/suggestions/issue-97677.fixed @@ -0,0 +1,8 @@ +// run-rustfix + +fn add_ten<N: std::ops::Add<i32, Output=N>>(n: N) -> N { + n + 10 + //~^ ERROR cannot add `{integer}` to `N` +} + +fn main() { add_ten(0); } diff --git a/src/test/ui/suggestions/issue-97677.rs b/src/test/ui/suggestions/issue-97677.rs index a4c3b1350b891..2abf2af33845c 100644 --- a/src/test/ui/suggestions/issue-97677.rs +++ b/src/test/ui/suggestions/issue-97677.rs @@ -1,6 +1,8 @@ +// run-rustfix + fn add_ten<N>(n: N) -> N { n + 10 //~^ ERROR cannot add `{integer}` to `N` } -fn main() {} +fn main() { add_ten(0); } diff --git a/src/test/ui/suggestions/issue-97677.stderr b/src/test/ui/suggestions/issue-97677.stderr index ea563ea844de5..069b184ac636c 100644 --- a/src/test/ui/suggestions/issue-97677.stderr +++ b/src/test/ui/suggestions/issue-97677.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `{integer}` to `N` - --> $DIR/issue-97677.rs:2:7 + --> $DIR/issue-97677.rs:4:7 | LL | n + 10 | - ^ -- {integer} @@ -8,8 +8,8 @@ LL | n + 10 | help: consider restricting type parameter `N` | -LL | fn add_ten<N: std::ops::Add<i32>>(n: N) -> N { - | ++++++++++++++++++++ +LL | fn add_ten<N: std::ops::Add<i32, Output=N>>(n: N) -> N { + | ++++++++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-98500.rs b/src/test/ui/suggestions/issue-98500.rs new file mode 100644 index 0000000000000..a2717fd9206d1 --- /dev/null +++ b/src/test/ui/suggestions/issue-98500.rs @@ -0,0 +1,14 @@ +// aux-build:not-object-safe.rs + +extern crate not_object_safe; + +pub trait B where + Self: not_object_safe::A, +{ + fn f2(&self); +} + +struct S(Box<dyn B>); +//~^ ERROR the trait `B` cannot be made into an object + +fn main() {} diff --git a/src/test/ui/suggestions/issue-98500.stderr b/src/test/ui/suggestions/issue-98500.stderr new file mode 100644 index 0000000000000..e7251d735e38e --- /dev/null +++ b/src/test/ui/suggestions/issue-98500.stderr @@ -0,0 +1,24 @@ +error[E0038]: the trait `B` cannot be made into an object + --> $DIR/issue-98500.rs:11:14 + | +LL | struct S(Box<dyn B>); + | ^^^^^ `B` 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/auxiliary/not-object-safe.rs:4:8 + | +LL | fn f(); + | ^ ...because associated function `f` has no `self` parameter +LL | fn f2(self: &Arc<Self>); + | ^^ ...because method `f2`'s `self` parameter cannot be dispatched on + | + ::: $DIR/issue-98500.rs:5:11 + | +LL | pub trait B where + | - this trait cannot be made into an object... + = help: consider moving `f` to another trait + = help: consider moving `f2` to another trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/suggestions/issue-99080.rs b/src/test/ui/suggestions/issue-99080.rs new file mode 100644 index 0000000000000..91f574f35b80b --- /dev/null +++ b/src/test/ui/suggestions/issue-99080.rs @@ -0,0 +1,16 @@ +// aux-build:meow.rs + +extern crate meow; + +use meow::Meow; + +fn needs_meow<T: Meow>(t: T) {} + +fn main() { + needs_meow(1usize); + //~^ ERROR the trait bound `usize: Meow` is not satisfied +} + +struct LocalMeow; + +impl Meow for LocalMeow {} diff --git a/src/test/ui/suggestions/issue-99080.stderr b/src/test/ui/suggestions/issue-99080.stderr new file mode 100644 index 0000000000000..d1908dd9d0d86 --- /dev/null +++ b/src/test/ui/suggestions/issue-99080.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `usize: Meow` is not satisfied + --> $DIR/issue-99080.rs:10:16 + | +LL | needs_meow(1usize); + | ---------- ^^^^^^ the trait `Meow` is not implemented for `usize` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Meow`: + GlobalMeow + LocalMeow +note: required by a bound in `needs_meow` + --> $DIR/issue-99080.rs:7:18 + | +LL | fn needs_meow<T: Meow>(t: T) {} + | ^^^^ required by this bound in `needs_meow` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 85c534364b66e..e3fe25d5f9c97 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,7 +10,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() - | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here + | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 19:12]` captures the anonymous lifetime defined here ... LL | / move || { LL | | diff --git a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr index ee29a56f3f8c5..4c75fbe4c786b 100644 --- a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr +++ b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.stderr @@ -2,7 +2,7 @@ error[E0046]: not all trait items implemented, missing: `Type`, `bar`, `baz` --> $DIR/missing-assoc-fn-applicable-suggestions.rs:15:1 | LL | type Type; - | ---------- `Type` from trait + | --------- `Type` from trait LL | fn bar<T>(_: T) -> Self; | ------------------------ `bar` from trait LL | fn baz<T>(_: T) -> Self where T: TraitB, <T as TraitB>::Item: Copy; diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed index 73bb6725f5a72..69487c565c933 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed @@ -2,7 +2,7 @@ #![allow(unused_variables, dead_code)] trait Trait { - fn foo(&self) where Self: Other, Self: Sized, { } + fn foo(&self) where Self: Other, Self: Sized { } fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type } diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr index 74237e6e6c638..c0dc71df06e65 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr @@ -1,12 +1,3 @@ -error[E0307]: invalid `self` parameter type: () - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:6:18 - | -LL | fn bar(self: ()) {} - | ^^ - | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) - error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:12 | @@ -28,13 +19,22 @@ LL | fn foo(&self) where Self: Other, { } | +++++ help: alternatively, consider constraining `foo` so it does not apply to trait objects | -LL | fn foo() where Self: Other, Self: Sized, { } - | +++++++++++++ +LL | fn foo() where Self: Other, Self: Sized { } + | ~~~~~~~~~~~~~ help: consider changing method `bar`'s `self` parameter to be `&self` | LL | fn bar(self: &Self) {} | ~~~~~ +error[E0307]: invalid `self` parameter type: () + --> $DIR/object-unsafe-trait-should-use-where-sized.rs:6:18 + | +LL | fn bar(self: ()) {} + | ^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0307. diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr index a9e540084e590..fccfbe1d744c2 100644 --- a/src/test/ui/suggestions/option-content-move.stderr +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -2,23 +2,37 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared referenc --> $DIR/option-content-move.rs:11:20 | LL | if selection.1.unwrap().contains(selection.0) { - | ^^^^^^^^^^^ move occurs because `selection.1` has type `Option<String>`, which does not implement the `Copy` trait + | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call + | | + | move occurs because `selection.1` has type `Option<String>`, which does not implement the `Copy` trait | -help: consider borrowing the `Option`'s content +note: this function takes ownership of the receiver `self`, which moves `selection.1` + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ +help: consider calling `.as_ref()` to borrow the type's contents | LL | if selection.1.as_ref().unwrap().contains(selection.0) { - | +++++++++ + | +++++++++ error[E0507]: cannot move out of `selection.1` which is behind a shared reference --> $DIR/option-content-move.rs:29:20 | LL | if selection.1.unwrap().contains(selection.0) { - | ^^^^^^^^^^^ move occurs because `selection.1` has type `Result<String, String>`, which does not implement the `Copy` trait + | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call + | | + | move occurs because `selection.1` has type `Result<String, String>`, which does not implement the `Copy` trait + | +note: this function takes ownership of the receiver `self`, which moves `selection.1` + --> $SRC_DIR/core/src/result.rs:LL:COL | -help: consider borrowing the `Result`'s content +LL | pub fn unwrap(self) -> T + | ^^^^ +help: consider calling `.as_ref()` to borrow the type's contents | LL | if selection.1.as_ref().unwrap().contains(selection.0) { - | +++++++++ + | +++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr index 16cbbaba512a4..1d3dff3be3476 100644 --- a/src/test/ui/suggestions/option-content-move2.stderr +++ b/src/test/ui/suggestions/option-content-move2.stderr @@ -1,22 +1,19 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure --> $DIR/option-content-move2.rs:9:9 | -LL | let mut var = None; - | ------- captured outer variable -LL | func(|| { - | __________- -LL | | // Shouldn't suggest `move ||.as_ref()` here -LL | | move || { - | | ^^^^^^^ move out of `var` occurs here -LL | | -LL | | var = Some(NotCopyable); - | | --- - | | | - | | variable moved due to use in closure - | | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait -LL | | } -LL | | }); - | |_____- captured by this `FnMut` closure +LL | let mut var = None; + | ------- captured outer variable +LL | func(|| { + | -- captured by this `FnMut` closure +LL | // Shouldn't suggest `move ||.as_ref()` here +LL | move || { + | ^^^^^^^ move out of `var` occurs here +LL | +LL | var = Some(NotCopyable); + | --- + | | + | variable moved due to use in closure + | move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/parenthesized-deref-suggestion.rs b/src/test/ui/suggestions/parenthesized-deref-suggestion.rs similarity index 100% rename from src/test/ui/parenthesized-deref-suggestion.rs rename to src/test/ui/suggestions/parenthesized-deref-suggestion.rs diff --git a/src/test/ui/parenthesized-deref-suggestion.stderr b/src/test/ui/suggestions/parenthesized-deref-suggestion.stderr similarity index 100% rename from src/test/ui/parenthesized-deref-suggestion.stderr rename to src/test/ui/suggestions/parenthesized-deref-suggestion.stderr diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr index f1c0cd6b543e4..3fb418b1c0aac 100644 --- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `default_hello` found for struct `GenericAssocMeth --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:9:7 | LL | struct GenericAssocMethod<T>(T); - | -------------------------------- method `default_hello` not found for this + | ---------------------------- method `default_hello` not found for this struct ... LL | x.default_hello(); | --^^^^^^^^^^^^^ diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs new file mode 100644 index 0000000000000..7cf536f7966e0 --- /dev/null +++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs @@ -0,0 +1,58 @@ +// Ensure that the compiler include the blanklet implementation suggestion +// when inside a `impl` statment are used two local traits. +// +// edition:2021 +use std::fmt; + +trait LocalTraitOne { } + +trait LocalTraitTwo { } + +trait GenericTrait<T> {} + +impl LocalTraitTwo for LocalTraitOne {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne` + +impl fmt::Display for LocalTraitOne { +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!(); + } +} + +impl fmt::Display for LocalTraitTwo + Send { +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!(); + } +} + +impl LocalTraitOne for fmt::Display {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display` + + +impl LocalTraitOne for fmt::Display + Send {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send` + + +impl<E> GenericTrait<E> for LocalTraitOne {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne` + +trait GenericTraitTwo<T> {} + +impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>` + +fn main() {} diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr new file mode 100644 index 0000000000000..d739a8272f152 --- /dev/null +++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr @@ -0,0 +1,107 @@ +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:13:24 + | +LL | impl LocalTraitTwo for LocalTraitOne {} + | ^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl LocalTraitTwo for LocalTraitOne {} +LL + impl LocalTraitTwo for dyn LocalTraitOne {} + | +help: alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne` + | +LL | impl<T: LocalTraitOne> LocalTraitTwo for T {} + | ++++++++++++++++++ ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:18:23 + | +LL | impl fmt::Display for LocalTraitOne { + | ^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl fmt::Display for LocalTraitOne { +LL + impl fmt::Display for dyn LocalTraitOne { + | + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:26:23 + | +LL | impl fmt::Display for LocalTraitTwo + Send { + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl fmt::Display for LocalTraitTwo + Send { +LL + impl fmt::Display for dyn LocalTraitTwo + Send { + | + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:34:24 + | +LL | impl LocalTraitOne for fmt::Display {} + | ^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl LocalTraitOne for fmt::Display {} +LL + impl LocalTraitOne for dyn fmt::Display {} + | +help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display` + | +LL | impl<T: fmt::Display> LocalTraitOne for T {} + | +++++++++++++++++ ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:40:24 + | +LL | impl LocalTraitOne for fmt::Display + Send {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl LocalTraitOne for fmt::Display + Send {} +LL + impl LocalTraitOne for dyn fmt::Display + Send {} + | +help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send` + | +LL | impl<T: fmt::Display + Send> LocalTraitOne for T {} + | ++++++++++++++++++++++++ ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:46:29 + | +LL | impl<E> GenericTrait<E> for LocalTraitOne {} + | ^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl<E> GenericTrait<E> for LocalTraitOne {} +LL + impl<E> GenericTrait<E> for dyn LocalTraitOne {} + | +help: alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne` + | +LL | impl<E, T: LocalTraitOne> GenericTrait<E> for T {} + | ++++++++++++++++++ ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-blanket-impl-local-trait.rs:53:35 + | +LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {} + | ^^^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {} +LL + impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {} + | +help: alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>` + | +LL | impl<T, E, U: GenericTrait<T>> GenericTraitTwo<E> for U {} + | ++++++++++++++++++++ ~ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0782`. diff --git a/src/test/ui/suggestions/suggest-borrow-to-dyn-object.rs b/src/test/ui/suggestions/suggest-borrow-to-dyn-object.rs new file mode 100644 index 0000000000000..120fc538307a7 --- /dev/null +++ b/src/test/ui/suggestions/suggest-borrow-to-dyn-object.rs @@ -0,0 +1,16 @@ +use std::ffi::{OsStr, OsString}; +use std::path::Path; + +fn check(p: &dyn AsRef<Path>) { + let m = std::fs::metadata(&p); + println!("{:?}", &m); +} + +fn main() { + let s: OsString = ".".into(); + let s: &OsStr = &s; + check(s); + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + //~| HELP within `OsStr`, the trait `Sized` is not implemented for `[u8]` + //~| HELP consider borrowing the value, since `&OsStr` can be coerced into `dyn AsRef<Path>` +} diff --git a/src/test/ui/suggestions/suggest-borrow-to-dyn-object.stderr b/src/test/ui/suggestions/suggest-borrow-to-dyn-object.stderr new file mode 100644 index 0000000000000..6b6e406130ec2 --- /dev/null +++ b/src/test/ui/suggestions/suggest-borrow-to-dyn-object.stderr @@ -0,0 +1,19 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/suggest-borrow-to-dyn-object.rs:12:11 + | +LL | check(s); + | ----- ^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: within `OsStr`, the trait `Sized` is not implemented for `[u8]` + = note: required because it appears within the type `OsStr` + = note: required for the cast from `OsStr` to the object type `dyn AsRef<Path>` +help: consider borrowing the value, since `&OsStr` can be coerced into `dyn AsRef<Path>` + | +LL | check(&s); + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-box.stderr b/src/test/ui/suggestions/suggest-box.stderr index d5c49a477b028..2bdaa4e9780eb 100644 --- a/src/test/ui/suggestions/suggest-box.stderr +++ b/src/test/ui/suggestions/suggest-box.stderr @@ -11,7 +11,7 @@ LL | | }; | |_____^ expected struct `Box`, found closure | = note: expected struct `Box<dyn Fn() -> Result<(), ()>>` - found closure `[closure@$DIR/suggest-box.rs:4:47: 7:6]` + found closure `[closure@$DIR/suggest-box.rs:4:47: 4:49]` = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html help: store this in the heap by calling `Box::new` | diff --git a/src/test/ui/suggestions/suggest-closure-return-type-1.stderr b/src/test/ui/suggestions/suggest-closure-return-type-1.stderr index 3116211b52c90..f4c2eb7ff34ae 100644 --- a/src/test/ui/suggestions/suggest-closure-return-type-1.stderr +++ b/src/test/ui/suggestions/suggest-closure-return-type-1.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `[_; 0]` --> $DIR/suggest-closure-return-type-1.rs:4:18 | LL | unbound_drop(|| -> _ { [] }); - | ^^^^^^^ + | ^^^^^^^ -- type must be known at this point | help: try giving this closure an explicit return type | diff --git a/src/test/ui/suggestions/suggest-closure-return-type-2.stderr b/src/test/ui/suggestions/suggest-closure-return-type-2.stderr index f368e7de467ca..88bf263043d2c 100644 --- a/src/test/ui/suggestions/suggest-closure-return-type-2.stderr +++ b/src/test/ui/suggestions/suggest-closure-return-type-2.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `[_; 0]` --> $DIR/suggest-closure-return-type-2.rs:4:18 | LL | unbound_drop(|| { [] }) - | ^^ + | ^^ -- type must be known at this point | help: try giving this closure an explicit return type | diff --git a/src/test/ui/suggestions/suggest-closure-return-type-3.stderr b/src/test/ui/suggestions/suggest-closure-return-type-3.stderr index 4176932153353..bc4107528d274 100644 --- a/src/test/ui/suggestions/suggest-closure-return-type-3.stderr +++ b/src/test/ui/suggestions/suggest-closure-return-type-3.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `[_; 0]` --> $DIR/suggest-closure-return-type-3.rs:4:18 | LL | unbound_drop(|| []); - | ^^ + | ^^ -- type must be known at this point | help: try giving this closure an explicit return type | diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index 9079e8f2ce7a4..97d7e6696a88c 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `bat` found for struct `Foo` in the current scope --> $DIR/suggest-methods.rs:18:7 | LL | struct Foo; - | ----------- method `bat` not found for this + | ---------- method `bat` not found for this struct ... LL | f.bat(1.0); | ^^^ help: there is an associated function with a similar name: `bar` diff --git a/src/test/ui/suggestions/suggest-on-bare-closure-call.rs b/src/test/ui/suggestions/suggest-on-bare-closure-call.rs index 355708c08ec2f..496c305bc2aff 100644 --- a/src/test/ui/suggestions/suggest-on-bare-closure-call.rs +++ b/src/test/ui/suggestions/suggest-on-bare-closure-call.rs @@ -1,4 +1,11 @@ +// edition:2021 + +#![feature(async_closure)] + fn main() { let _ = ||{}(); //~^ ERROR expected function, found `()` + + let _ = async ||{}(); + //~^ ERROR expected function, found `()` } diff --git a/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr b/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr index 81f2e498fe5de..e65a6eb4939d9 100644 --- a/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr +++ b/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found `()` - --> $DIR/suggest-on-bare-closure-call.rs:2:15 + --> $DIR/suggest-on-bare-closure-call.rs:6:15 | LL | let _ = ||{}(); | ^^-- @@ -11,6 +11,19 @@ help: if you meant to create this closure and immediately call it, surround the LL | let _ = (||{})(); | + + -error: aborting due to previous error +error[E0618]: expected function, found `()` + --> $DIR/suggest-on-bare-closure-call.rs:9:21 + | +LL | let _ = async ||{}(); + | ^^-- + | | + | call expression requires function + | +help: if you meant to create this closure and immediately call it, surround the closure with parentheses + | +LL | let _ = (async ||{})(); + | + + + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/suggestions/suggest-ref-macro.stderr b/src/test/ui/suggestions/suggest-ref-macro.stderr index b0ac770c06f0f..84cbc93571a71 100644 --- a/src/test/ui/suggestions/suggest-ref-macro.stderr +++ b/src/test/ui/suggestions/suggest-ref-macro.stderr @@ -1,3 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/suggest-ref-macro.rs:8:1 + | +LL | #[hello] + | ^^^^^^^^ + | | + | expected `&mut i32`, found integer + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/suggest-ref-macro.rs:8:1 + | +LL | #[hello] + | _-^^^^^^^ +LL | | fn abc() {} +LL | | +LL | | fn x(_: &mut i32) {} +LL | | +LL | | macro_rules! bla { + | |_____________- + = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> $DIR/suggest-ref-macro.rs:15:11 | @@ -36,28 +58,6 @@ note: function defined here LL | fn x(_: &mut i32) {} | ^ ----------- -error[E0308]: mismatched types - --> $DIR/suggest-ref-macro.rs:8:1 - | -LL | #[hello] - | ^^^^^^^^ - | | - | expected `&mut i32`, found integer - | arguments to this function are incorrect - | -note: function defined here - --> $DIR/suggest-ref-macro.rs:8:1 - | -LL | #[hello] - | _-^^^^^^^ -LL | | fn abc() {} -LL | | -LL | | fn x(_: &mut i32) {} -LL | | -LL | | macro_rules! bla { - | |_____________- - = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info) - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/suggest-trait-items.stderr b/src/test/ui/suggestions/suggest-trait-items.stderr index 4abc34466106d..8bc3df7b817e3 100644 --- a/src/test/ui/suggestions/suggest-trait-items.stderr +++ b/src/test/ui/suggestions/suggest-trait-items.stderr @@ -47,7 +47,7 @@ error[E0046]: not all trait items implemented, missing: `Type`, `foo`, `bar`, `q --> $DIR/suggest-trait-items.rs:11:1 | LL | type Type; - | ---------- `Type` from trait + | --------- `Type` from trait LL | LL | fn foo(); | --------- `foo` from trait @@ -63,7 +63,7 @@ error[E0046]: not all trait items implemented, missing: `Const` --> $DIR/suggest-trait-items.rs:40:1 | LL | const Const: i32; - | ----------------- `Const` from trait + | ---------------- `Const` from trait ... LL | impl Bar for B { | ^^^^^^^^^^^^^^ missing `Const` in implementation diff --git a/src/test/ui/suggestions/suggest-variants.stderr b/src/test/ui/suggestions/suggest-variants.stderr index 9227baa3e1a5c..a422bc6563541 100644 --- a/src/test/ui/suggestions/suggest-variants.stderr +++ b/src/test/ui/suggestions/suggest-variants.stderr @@ -29,7 +29,7 @@ error[E0599]: no variant or associated item named `Squareee` found for enum `Sha --> $DIR/suggest-variants.rs:15:12 | LL | enum Shape { - | ---------- variant or associated item `Squareee` not found here + | ---------- variant or associated item `Squareee` not found for this enum ... LL | Shape::Squareee; | ^^^^^^^^ @@ -41,7 +41,7 @@ error[E0599]: no variant or associated item named `Circl` found for enum `Shape` --> $DIR/suggest-variants.rs:16:12 | LL | enum Shape { - | ---------- variant or associated item `Circl` not found here + | ---------- variant or associated item `Circl` not found for this enum ... LL | Shape::Circl; | ^^^^^ @@ -53,7 +53,7 @@ error[E0599]: no variant or associated item named `Rombus` found for enum `Shape --> $DIR/suggest-variants.rs:17:12 | LL | enum Shape { - | ---------- variant or associated item `Rombus` not found here + | ---------- variant or associated item `Rombus` not found for this enum ... LL | Shape::Rombus; | ^^^^^^ variant or associated item not found in `Shape` diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr index 6127446c83e3b..de64269d1f191 100644 --- a/src/test/ui/suggestions/unnamable-types.stderr +++ b/src/test/ui/suggestions/unnamable-types.stderr @@ -19,7 +19,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures LL | const C: _ = || 42; | ^ not allowed in type signatures | -note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named +note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:16]` cannot be named --> $DIR/unnamable-types.rs:17:14 | LL | const C: _ = || 42; @@ -31,7 +31,7 @@ error: missing type for `const` item LL | const D = S { t: { let i = 0; move || -> i32 { i } } }; | ^ | -note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named +note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named --> $DIR/unnamable-types.rs:23:11 | LL | const D = S { t: { let i = 0; move || -> i32 { i } } }; @@ -55,7 +55,7 @@ error: missing type for `const` item LL | const G = || -> i32 { yield 0; return 1; }; | ^ | -note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43]` cannot be named +note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:20]` cannot be named --> $DIR/unnamable-types.rs:37:11 | LL | const G = || -> i32 { yield 0; return 1; }; diff --git a/src/test/ui/suggestions/use-placement-typeck.stderr b/src/test/ui/suggestions/use-placement-typeck.stderr index 21f22dade2c22..3b2749773a134 100644 --- a/src/test/ui/suggestions/use-placement-typeck.stderr +++ b/src/test/ui/suggestions/use-placement-typeck.stderr @@ -8,7 +8,7 @@ LL | fn abc(&self) {} | --- the method is available for `S` here LL | } LL | pub struct S; - | ------------- method `abc` not found for this + | ------------ method `abc` not found for this struct | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr index 5409e32c436fb..7038a572bec07 100644 --- a/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr +++ b/src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr @@ -18,10 +18,10 @@ error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16 | LL | type A; - | ------- `A` defined here + | ------ `A` defined here LL | type B; LL | type C; - | ------- `C` defined here + | ------ `C` defined here ... LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified diff --git a/src/test/ui/tag-variant-disr-dup.stderr b/src/test/ui/tag-variant-disr-dup.stderr index 27adb6998aede..6b1ba43d2ba6e 100644 --- a/src/test/ui/tag-variant-disr-dup.stderr +++ b/src/test/ui/tag-variant-disr-dup.stderr @@ -1,17 +1,13 @@ error[E0081]: discriminant value `0` assigned more than once --> $DIR/tag-variant-disr-dup.rs:3:1 | -LL | / enum Color { -LL | | -LL | | Red = 0xff0000, -LL | | Green = 0x00ff00, -LL | | Blue = 0x0000ff, -LL | | Black = 0x000000, - | | -------- first assignment of `0` -LL | | White = 0x000000, - | | -------- second assignment of `0` -LL | | } - | |_^ +LL | enum Color { + | ^^^^^^^^^^ +... +LL | Black = 0x000000, + | -------- first assignment of `0` +LL | White = 0x000000, + | -------- second assignment of `0` error: aborting due to previous error diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index 25a2c1975e7b2..889ced9752bd4 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -34,43 +34,43 @@ LL | fn bar() {} = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:34:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | mod another {} - | -------------- not a function + | -------------- not a function definition -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:39:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | const FOO: usize = 7; - | --------------------- not a function + | --------------------- not a function definition -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:44:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct Foo; - | ----------- not a function + | ----------- not a function definition -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:49:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | enum Bar {} - | ----------- not a function + | ----------- not a function definition -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:54:1 | LL | #[target_feature(enable = "sse2")] @@ -81,16 +81,16 @@ LL | | LL | | f1: u16, LL | | f2: u16, LL | | } - | |_- not a function + | |_- not a function definition -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:62:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | trait Baz {} - | ------------ not a function + | ------------ not a function definition error: cannot use `#[inline(always)]` with `#[target_feature]` --> $DIR/invalid-attribute.rs:67:1 @@ -98,7 +98,7 @@ error: cannot use `#[inline(always)]` with `#[target_feature]` LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:85:5 | LL | #[target_feature(enable = "sse2")] @@ -108,16 +108,16 @@ LL | / unsafe { LL | | foo(); LL | | bar(); LL | | } - | |_____- not a function + | |_____- not a function definition -error: attribute should be applied to a function +error: attribute should be applied to a function definition --> $DIR/invalid-attribute.rs:93:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | || {}; - | ----- not a function + | ----- not a function definition error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions --> $DIR/invalid-attribute.rs:77:5 diff --git a/src/test/ui/terminal-width/flag-human.rs b/src/test/ui/terminal-width/flag-human.rs deleted file mode 100644 index e445a84fd012e..0000000000000 --- a/src/test/ui/terminal-width/flag-human.rs +++ /dev/null @@ -1,9 +0,0 @@ -// compile-flags: -Z terminal-width=20 - -// This test checks that `-Z terminal-width` effects the human error output by restricting it to an -// arbitrarily low value so that the effect is visible. - -fn main() { - let _: () = 42; - //~^ ERROR mismatched types -} diff --git a/src/test/ui/terminal-width/flag-json.rs b/src/test/ui/terminal-width/flag-json.rs deleted file mode 100644 index 3d2530e204b33..0000000000000 --- a/src/test/ui/terminal-width/flag-json.rs +++ /dev/null @@ -1,9 +0,0 @@ -// compile-flags: -Z terminal-width=20 --error-format=json - -// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an -// arbitrarily low value so that the effect is visible. - -fn main() { - let _: () = 42; - //~^ ERROR arguments to this function are incorrect -} diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs new file mode 100644 index 0000000000000..557d890882b5e --- /dev/null +++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs @@ -0,0 +1,33 @@ +struct Victim<'a, T: Perpetrator + ?Sized> { + value: u8, + perp: &'a T, +} + +trait VictimTrait { + type Ret; + fn get(self) -> Self::Ret; +} + +// Actual fix is here +impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> { + type Ret = u8; + fn get(self) -> Self::Ret { + self.value + } +} + +trait Perpetrator { + fn getter<'a>(&'a self) -> Victim<'a, Self> { + Victim { + value: 0, + perp: self, + } + } + + fn trigger(&self) { + self.getter().get(); + //~^ ERROR the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied + } +} + +fn main() {} diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr new file mode 100644 index 0000000000000..543ceac8e9178 --- /dev/null +++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr @@ -0,0 +1,31 @@ +error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied + --> $DIR/impl-derived-implicit-sized-bound-2.rs:28:19 + | +LL | struct Victim<'a, T: Perpetrator + ?Sized> { + | ------------------------------------------ + | | + | method `get` not found for this struct + | doesn't satisfy `Victim<'_, Self>: VictimTrait` +... +LL | self.getter().get(); + | ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds + | +note: trait bound `Self: Sized` was not satisfied + --> $DIR/impl-derived-implicit-sized-bound-2.rs:12:10 + | +LL | impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> { + | ^ ----------- ------------- + | | + | unsatisfied trait bound introduced here +help: consider relaxing the type parameter's implicit `Sized` bound + | +LL | impl<'a, T: ?Sized + Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> { + | ++++++++ +help: consider restricting the type parameter to satisfy the trait bound + | +LL | struct Victim<'a, T: Perpetrator + ?Sized> where Self: Sized { + | +++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs new file mode 100644 index 0000000000000..28da41a0ca5f5 --- /dev/null +++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs @@ -0,0 +1,36 @@ +struct Victim<'a, T: Perpetrator + ?Sized> +where + Self: Sized +{ + value: u8, + perp: &'a T, +} + +trait VictimTrait { + type Ret; + fn get(self) -> Self::Ret; +} + +// Actual fix is here +impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> { + type Ret = u8; + fn get(self) -> Self::Ret { + self.value + } +} + +trait Perpetrator { + fn getter<'a>(&'a self) -> Victim<'a, Self> { + Victim { + value: 0, + perp: self, + } + } + + fn trigger(&self) { + self.getter().get(); + //~^ ERROR the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied + } +} + +fn main() {} diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr new file mode 100644 index 0000000000000..f08d685836ec1 --- /dev/null +++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr @@ -0,0 +1,31 @@ +error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied + --> $DIR/impl-derived-implicit-sized-bound.rs:31:19 + | +LL | struct Victim<'a, T: Perpetrator + ?Sized> + | ------------------------------------------ + | | + | method `get` not found for this struct + | doesn't satisfy `Victim<'_, Self>: VictimTrait` +... +LL | self.getter().get(); + | ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds + | +note: trait bound `Self: Sized` was not satisfied + --> $DIR/impl-derived-implicit-sized-bound.rs:15:10 + | +LL | impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> { + | ^ ----------- ------------- + | | + | unsatisfied trait bound introduced here +help: consider relaxing the type parameter's implicit `Sized` bound + | +LL | impl<'a, T: ?Sized + Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> { + | ++++++++ +help: consider restricting the type parameter to satisfy the trait bound + | +LL | Self: Sized, Self: Sized + | +++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs b/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs deleted file mode 100644 index 288b2098b4c02..0000000000000 --- a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs +++ /dev/null @@ -1,43 +0,0 @@ -// known-bug -// build-fail -// failure-status: 101 -// compile-flags:--crate-type=lib -Zmir-opt-level=3 -// rustc-env:RUST_BACKTRACE=0 - -// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" -// normalize-stderr-test "error: internal compiler error.*" -> "error: internal compiler error" -// normalize-stderr-test "encountered.*with incompatible types:" "encountered ... with incompatible types:" -// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" -// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" -// normalize-stderr-test "note: compiler flags.*\n\n" -> "" -// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" -// normalize-stderr-test "query stack during panic:\n" -> "" -// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" -// normalize-stderr-test "end of query stack\n" -> "" -// normalize-stderr-test "#.*\n" -> "" - -// This is a known bug that @compiler-errors tried to fix in #94238, -// but the solution was probably not correct. - -pub trait Factory<T> { - type Item; -} - -pub struct IntFactory; - -impl<T> Factory<T> for IntFactory { - type Item = usize; -} - -pub fn foo<T>() -where - IntFactory: Factory<T>, -{ - let mut x: <IntFactory as Factory<T>>::Item = bar::<T>(); -} - -#[inline] -pub fn bar<T>() -> <IntFactory as Factory<T>>::Item { - 0usize -} diff --git a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr b/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr deleted file mode 100644 index 56cc5c93c96f2..0000000000000 --- a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: internal compiler error - -error: internal compiler error - encountered ... with incompatible types: - left-hand side has type: <IntFactory as Factory<T>>::Item - right-hand side has type: usize - --> $DIR/select-param-env-instead-of-blanket.rs:42:5 - | -LL | let mut x: <IntFactory as Factory<T>>::Item = bar::<T>(); - | ---------- in this inlined function call -... -LL | 0usize - | ^^^^^^ - | - = note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:128:36 - -thread 'rustc' panicked - diff --git a/src/test/ui/traits/alias/issue-83613.stderr b/src/test/ui/traits/alias/issue-83613.stderr index bbc240b6aec49..b9d93160192e9 100644 --- a/src/test/ui/traits/alias/issue-83613.stderr +++ b/src/test/ui/traits/alias/issue-83613.stderr @@ -1,3 +1,11 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType` + --> $DIR/issue-83613.rs:10:1 + | +LL | impl<T: Send> AnotherTrait for T {} + | -------------------------------- first implementation here +LL | impl AnotherTrait for OpaqueType {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType` + error: cannot implement trait on type alias impl trait --> $DIR/issue-83613.rs:10:23 | @@ -10,14 +18,6 @@ note: type alias impl trait defined here LL | type OpaqueType = impl OpaqueTrait; | ^^^^^^^^^^^^^^^^ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `OpaqueType` - --> $DIR/issue-83613.rs:10:1 - | -LL | impl<T: Send> AnotherTrait for T {} - | -------------------------------- first implementation here -LL | impl AnotherTrait for OpaqueType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType` - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/alias/only-maybe-bound.stderr b/src/test/ui/traits/alias/only-maybe-bound.stderr index 06c707e4332a5..175ec8120ecc6 100644 --- a/src/test/ui/traits/alias/only-maybe-bound.stderr +++ b/src/test/ui/traits/alias/only-maybe-bound.stderr @@ -2,7 +2,7 @@ error[E0224]: at least one trait is required for an object type --> $DIR/only-maybe-bound.rs:13:12 | LL | trait _1 = _0; - | -------------- this alias does not contain a trait + | -------- this alias does not contain a trait ... LL | type _T0 = dyn _1; | ^^^^^^ @@ -11,7 +11,7 @@ error[E0224]: at least one trait is required for an object type --> $DIR/only-maybe-bound.rs:19:12 | LL | trait _2 = _1 + _1; - | ------------------- this alias does not contain a trait + | -------- this alias does not contain a trait LL | LL | type _T1 = dyn _2; | ^^^^^^ diff --git a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index 115539a6dc28d..6ce57b6263e41 100644 --- a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -15,7 +15,6 @@ LL | s.strip_suffix(b'\n').unwrap_or(s) &'c &'b str [char; N] char - pattern::MultiCharEqPattern<C> = note: required because of the requirements on the impl of `Pattern<'_>` for `u8` error: aborting due to previous error diff --git a/src/test/ui/traits/bound/same-crate-name.stderr b/src/test/ui/traits/bound/same-crate-name.stderr index ef39a70066db6..f66cad77fcd1e 100644 --- a/src/test/ui/traits/bound/same-crate-name.stderr +++ b/src/test/ui/traits/bound/same-crate-name.stderr @@ -10,7 +10,7 @@ help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:5:1 | LL | impl Bar for Foo {} - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? = help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>` note: required by a bound in `try_foo` @@ -46,7 +46,7 @@ help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:13:1 | LL | impl Bar for ImplementsWrongTraitConditionally<isize> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? = help: the trait `main::a::Bar` is implemented for `ImplementsTraitForUsize<usize>` note: required by a bound in `try_foo` diff --git a/src/test/ui/traits/coercion-generic-bad.stderr b/src/test/ui/traits/coercion-generic-bad.stderr index b213ee635df59..93d6770eb47d1 100644 --- a/src/test/ui/traits/coercion-generic-bad.stderr +++ b/src/test/ui/traits/coercion-generic-bad.stderr @@ -5,7 +5,7 @@ LL | let s: Box<dyn Trait<isize>> = Box::new(Struct { person: "Fred" }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<isize>` is not implemented for `Struct` | = help: the trait `Trait<&'static str>` is implemented for `Struct` - = note: required for the cast to the object type `dyn Trait<isize>` + = note: required for the cast from `Struct` to the object type `dyn Trait<isize>` error: aborting due to previous error diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr index cc540ea905a10..afdad160919f9 100644 --- a/src/test/ui/traits/copy-impl-cannot-normalize.stderr +++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: TraitFoo` is not satisfied --> $DIR/copy-impl-cannot-normalize.rs:22:1 | LL | impl<T> Copy for Foo<T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs index d9de6d5edb9b4..1f896da94db57 100644 --- a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs +++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs @@ -36,11 +36,11 @@ trait Tr5 { } #[rustc_must_implement_one_of(abc, xyz)] -//~^ attribute can only be applied to a trait +//~^ attribute should be applied to a trait fn function() {} #[rustc_must_implement_one_of(abc, xyz)] -//~^ attribute can only be applied to a trait +//~^ attribute should be applied to a trait struct Struct {} fn main() {} diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr index bc28dc2c4f40d..869184f0d1a69 100644 --- a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr +++ b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr @@ -4,7 +4,7 @@ error: malformed `rustc_must_implement_one_of` attribute input LL | #[rustc_must_implement_one_of] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]` -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/rustc_must_implement_one_of_misuse.rs:38:1 | LL | #[rustc_must_implement_one_of(abc, xyz)] @@ -13,7 +13,7 @@ LL | LL | fn function() {} | ---------------- not a trait -error: attribute can only be applied to a trait +error: attribute should be applied to a trait --> $DIR/rustc_must_implement_one_of_misuse.rs:42:1 | LL | #[rustc_must_implement_one_of(abc, xyz)] diff --git a/src/test/ui/traits/issue-33140-hack-boundaries.stderr b/src/test/ui/traits/issue-33140-hack-boundaries.stderr index c87f1ff1f3f15..62cfca545b261 100644 --- a/src/test/ui/traits/issue-33140-hack-boundaries.stderr +++ b/src/test/ui/traits/issue-33140-hack-boundaries.stderr @@ -60,7 +60,7 @@ error[E0119]: conflicting implementations of trait `Trait5` for type `(dyn std:: LL | impl Trait5 for dyn Send {} | ------------------------ first implementation here LL | impl Trait5 for dyn Send where u32: Copy {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)` error: aborting due to 8 previous errors diff --git a/src/test/ui/traits/issue-3973.stderr b/src/test/ui/traits/issue-3973.stderr index 63282e8d86d7b..87ee08049300f 100644 --- a/src/test/ui/traits/issue-3973.stderr +++ b/src/test/ui/traits/issue-3973.stderr @@ -11,7 +11,7 @@ error[E0599]: no function or associated item named `new` found for struct `Point --> $DIR/issue-3973.rs:22:20 | LL | struct Point { - | ------------ function or associated item `new` not found for this + | ------------ function or associated item `new` not found for this struct ... LL | let p = Point::new(0.0, 0.0); | ^^^ function or associated item not found in `Point` diff --git a/src/test/ui/traits/issue-59029-1.stderr b/src/test/ui/traits/issue-59029-1.stderr index 53cdb8b1baf4c..203a89285306d 100644 --- a/src/test/ui/traits/issue-59029-1.stderr +++ b/src/test/ui/traits/issue-59029-1.stderr @@ -2,13 +2,13 @@ error[E0220]: associated type `Res` not found for `Self` --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>; - | ^^^ associated type `Res` not found + | ^^^ there is a similarly named associated type `Res` in the trait `Svc` error[E0220]: associated type `Res` not found for `Self` --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>; - | ^^^ associated type `Res` not found + | ^^^ there is a similarly named associated type `Res` in the trait `Svc` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr index 35d41c6266761..ae33e61d83b7a 100644 --- a/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr +++ b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr @@ -1,6 +1,8 @@ error[E0599]: no method named `foo` found for type parameter `T` in the current scope --> $DIR/issue-65284-suggest-generic-trait-bound.rs:8:7 | +LL | fn do_stuff<T : Bar>(t : T) { + | - method `foo` not found for this type parameter LL | t.foo() | ^^^ method not found in `T` | diff --git a/src/test/ui/traits/issue-65673.stderr b/src/test/ui/traits/issue-65673.stderr index 71f3a0e7c7caa..8f01d7c53e771 100644 --- a/src/test/ui/traits/issue-65673.stderr +++ b/src/test/ui/traits/issue-65673.stderr @@ -2,7 +2,7 @@ error[E0224]: at least one trait is required for an object type --> $DIR/issue-65673.rs:9:16 | LL | trait Alias<T> = where T: Trait; - | -------------------------------- this alias does not contain a trait + | -------------- this alias does not contain a trait ... LL | type Ctx = dyn Alias<T>; | ^^^^^^^^^^^^ diff --git a/src/test/ui/traits/issue-71036.stderr b/src/test/ui/traits/issue-71036.stderr index db1f694666085..3ee6db40e8736 100644 --- a/src/test/ui/traits/issue-71036.stderr +++ b/src/test/ui/traits/issue-71036.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied --> $DIR/issue-71036.rs:11:1 | LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` | = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T` diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr index 5aa42b5b1d3ed..2b832e27c5224 100644 --- a/src/test/ui/traits/issue-77982.stderr +++ b/src/test/ui/traits/issue-77982.stderr @@ -13,10 +13,6 @@ note: required by a bound in `HashMap::<K, V, S>::get` | LL | K: Borrow<Q>, | ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get` -help: consider specifying the generic argument - | -LL | opts.get::<Q>(opt.as_ref()); - | +++++ help: consider specifying the type argument in the function call | LL | opts.get::<Q>(opt.as_ref()); @@ -26,7 +22,9 @@ error[E0283]: type annotations needed --> $DIR/issue-77982.rs:8:10 | LL | opts.get(opt.as_ref()); - | ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get` + | ^^^ ------ type must be known at this point + | | + | cannot infer type of the type parameter `Q` declared on the associated function `get` | = note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`: - impl AsRef<OsStr> for String; @@ -42,7 +40,9 @@ error[E0283]: type annotations needed --> $DIR/issue-77982.rs:13:59 | LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(); - | ^^^^ + | --------- ^^^^ + | | + | type must be known at this point | = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`: - impl From<Ipv4Addr> for u32; @@ -59,7 +59,7 @@ error[E0283]: type annotations needed for `Box<T>` --> $DIR/issue-77982.rs:36:9 | LL | let _ = ().foo(); - | ^ + | ^ --- type must be known at this point | note: multiple `impl`s satisfying `(): Foo<'_, _>` found --> $DIR/issue-77982.rs:29:1 @@ -77,7 +77,7 @@ error[E0283]: type annotations needed for `Box<T>` --> $DIR/issue-77982.rs:40:9 | LL | let _ = (&()).bar(); - | ^ + | ^ --- type must be known at this point | note: multiple `impl`s satisfying `&(): Bar<'_, _>` found --> $DIR/issue-77982.rs:32:1 diff --git a/src/test/ui/traits/issue-78372.rs b/src/test/ui/traits/issue-78372.rs index 77a8c92c81c7e..92f9f4b467a97 100644 --- a/src/test/ui/traits/issue-78372.rs +++ b/src/test/ui/traits/issue-78372.rs @@ -4,7 +4,6 @@ impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} //~ ERROR cannot find type `U` //~^ ERROR cannot find type `MISC` in this scope //~| ERROR use of unstable library feature 'dispatch_from_dyn' //~| ERROR the trait `DispatchFromDyn` may only be implemented for a coercion between structures -//~| ERROR type parameter `T` must be covered by another type when it appears before the first trait Foo: X<u32> {} trait X<T> { fn foo(self: Smaht<Self, T>); diff --git a/src/test/ui/traits/issue-78372.stderr b/src/test/ui/traits/issue-78372.stderr index 49a9f47936876..7e781016e1f0f 100644 --- a/src/test/ui/traits/issue-78372.stderr +++ b/src/test/ui/traits/issue-78372.stderr @@ -50,22 +50,13 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} | = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable -error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`) - --> $DIR/issue-78372.rs:3:6 - | -LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} - | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`) - | - = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type - = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last - error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures --> $DIR/issue-78372.rs:3:1 | LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0210, E0378, E0412, E0658. -For more information about an error, try `rustc --explain E0210`. +Some errors have detailed explanations: E0378, E0412, E0658. +For more information about an error, try `rustc --explain E0378`. diff --git a/src/test/ui/traits/issue-8153.stderr b/src/test/ui/traits/issue-8153.stderr index 4389c3dc288f6..b76bbc0235fde 100644 --- a/src/test/ui/traits/issue-8153.stderr +++ b/src/test/ui/traits/issue-8153.stderr @@ -2,9 +2,9 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/issue-8153.rs:11:5 | LL | fn bar(&self) -> isize {1} - | -------------------------- previous definition of `bar` here + | ---------------------- previous definition of `bar` here LL | fn bar(&self) -> isize {2} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error diff --git a/src/test/ui/traits/issue-85735.rs b/src/test/ui/traits/issue-85735.rs index 16e874ee21e62..fb387a9c90965 100644 --- a/src/test/ui/traits/issue-85735.rs +++ b/src/test/ui/traits/issue-85735.rs @@ -5,7 +5,7 @@ trait Foo {} impl<'a, 'b, T> Foo for T where T: FnMut(&'a ()), - //~^ ERROR: type annotations needed [E0283] + //~^ ERROR: type annotations needed T: FnMut(&'b ()), { } diff --git a/src/test/ui/traits/issue-85735.stderr b/src/test/ui/traits/issue-85735.stderr index 33b12ef09ec26..fa280135beb2d 100644 --- a/src/test/ui/traits/issue-85735.stderr +++ b/src/test/ui/traits/issue-85735.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>` --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()), - | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^ | = note: cannot satisfy `T: FnMut<(&'a (),)>` diff --git a/src/test/ui/traits/issue-87558.rs b/src/test/ui/traits/issue-87558.rs new file mode 100644 index 0000000000000..c5d86bd637b2b --- /dev/null +++ b/src/test/ui/traits/issue-87558.rs @@ -0,0 +1,9 @@ +struct ErrorKind; +struct Error(ErrorKind); +impl Fn(&isize) for Error { + //~^ ERROR manual implementations of `Fn` are experimental + //~| ERROR associated type bindings are not allowed here + fn from() {} //~ ERROR method `from` is not a member of trait `Fn` +} + +fn main() {} diff --git a/src/test/ui/traits/issue-87558.stderr b/src/test/ui/traits/issue-87558.stderr new file mode 100644 index 0000000000000..494274d8c3075 --- /dev/null +++ b/src/test/ui/traits/issue-87558.stderr @@ -0,0 +1,24 @@ +error[E0407]: method `from` is not a member of trait `Fn` + --> $DIR/issue-87558.rs:6:5 + | +LL | fn from() {} + | ^^^^^^^^^^^^ not a member of trait `Fn` + +error[E0183]: manual implementations of `Fn` are experimental + --> $DIR/issue-87558.rs:3:6 + | +LL | impl Fn(&isize) for Error { + | ^^^^^^^^^^ manual implementations of `Fn` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-87558.rs:3:6 + | +LL | impl Fn(&isize) for Error { + | ^^^^^^^^^^ associated type not allowed here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0183, E0229, E0407. +For more information about an error, try `rustc --explain E0183`. diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.rs b/src/test/ui/traits/issue-91949-hangs-on-recursion.rs index cf2218fe52292..499a64f281699 100644 --- a/src/test/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,4 +1,5 @@ // build-fail +// compile-flags: -Zinline-mir=no // error-pattern: overflow evaluating the requirement `(): Sized` // error-pattern: function cannot return without recursing diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr index 6c04616344f54..86dbd0aac0310 100644 --- a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-91949-hangs-on-recursion.rs:21:1 + --> $DIR/issue-91949-hangs-on-recursion.rs:22:1 | LL | / fn recurse<T>(elements: T) -> Vec<char> LL | | where @@ -18,7 +18,7 @@ error[E0275]: overflow evaluating the requirement `(): Sized` = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) = note: required because of the requirements on the impl of `Iterator` for `std::iter::Empty<()>` = note: 171 redundant requirements hidden - = note: required because of the requirements on the impl of `Iterator` for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), std::iter::Empty<()>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>` + = note: required because of the requirements on the impl of `Iterator` for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), std::iter::Empty<()>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/traits/issue-95898.stderr b/src/test/ui/traits/issue-95898.stderr index 0a58ad4b663eb..ca7bacdbf41ba 100644 --- a/src/test/ui/traits/issue-95898.stderr +++ b/src/test/ui/traits/issue-95898.stderr @@ -1,6 +1,8 @@ error[E0599]: no method named `clone` found for type parameter `T` in the current scope --> $DIR/issue-95898.rs:5:7 | +LL | fn foo<T:>(t: T) { + | - method `clone` not found for this type parameter LL | t.clone(); | ^^^^^ method not found in `T` | diff --git a/src/test/ui/traits/item-privacy.stderr b/src/test/ui/traits/item-privacy.stderr index ef5d5cdff8f4b..7f78b37ba841d 100644 --- a/src/test/ui/traits/item-privacy.stderr +++ b/src/test/ui/traits/item-privacy.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `a` found for struct `S` in the current scope --> $DIR/item-privacy.rs:67:7 | LL | struct S; - | --------- method `a` not found for this + | -------- method `a` not found for this struct ... LL | S.a(); | ^ method not found in `S` @@ -18,7 +18,7 @@ error[E0599]: no method named `b` found for struct `S` in the current scope --> $DIR/item-privacy.rs:68:7 | LL | struct S; - | --------- method `b` not found for this + | -------- method `b` not found for this struct ... LL | fn b(&self) { } | - the method is available for `S` here @@ -45,7 +45,7 @@ error[E0599]: no function or associated item named `a` found for struct `S` in t --> $DIR/item-privacy.rs:78:8 | LL | struct S; - | --------- function or associated item `a` not found for this + | -------- function or associated item `a` not found for this struct ... LL | S::a(&S); | ^ function or associated item not found in `S` @@ -61,7 +61,7 @@ error[E0599]: no function or associated item named `b` found for struct `S` in t --> $DIR/item-privacy.rs:80:8 | LL | struct S; - | --------- function or associated item `b` not found for this + | -------- function or associated item `b` not found for this struct ... LL | S::b(&S); | ^ function or associated item not found in `S` @@ -85,7 +85,7 @@ error[E0599]: no associated item named `A` found for struct `S` in the current s --> $DIR/item-privacy.rs:97:8 | LL | struct S; - | --------- associated item `A` not found for this + | -------- associated item `A` not found for this struct ... LL | S::A; | ^ associated item not found in `S` @@ -101,7 +101,7 @@ error[E0599]: no associated item named `B` found for struct `S` in the current s --> $DIR/item-privacy.rs:98:8 | LL | struct S; - | --------- associated item `B` not found for this + | -------- associated item `B` not found for this struct ... LL | S::B; | ^ associated item not found in `S` @@ -116,7 +116,7 @@ error[E0624]: associated constant `A` is private --> $DIR/item-privacy.rs:101:14 | LL | const A: u8 = 0; - | ---------------- private associated constant defined here + | ----------- private associated constant defined here ... LL | <dyn C>::A; | ^ private associated constant diff --git a/src/test/ui/traits/map-types.stderr b/src/test/ui/traits/map-types.stderr index a4686edb71757..f685c50b07d5b 100644 --- a/src/test/ui/traits/map-types.stderr +++ b/src/test/ui/traits/map-types.stderr @@ -5,7 +5,7 @@ LL | let y: Box<dyn Map<usize, isize>> = Box::new(x); | ^^^^^^^^^^^ the trait `Map<usize, isize>` is not implemented for `Box<dyn Map<isize, isize>>` | = help: the trait `Map<K, V>` is implemented for `HashMap<K, V>` - = note: required for the cast to the object type `dyn Map<usize, isize>` + = note: required for the cast from `Box<dyn Map<isize, isize>>` to the object type `dyn Map<usize, isize>` error: aborting due to previous error diff --git a/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr b/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr index 25f8d5383776d..cbec359342148 100644 --- a/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr +++ b/src/test/ui/traits/multidispatch-convert-ambig-dest.stderr @@ -30,10 +30,6 @@ LL | fn test<T,U>(_: T, _: U) | ---- required by a bound in this LL | where T : Convert<U> | ^^^^^^^^^^ required by this bound in `test` -help: consider specifying the generic arguments - | -LL | test::<i32, U>(22, std::default::Default::default()); - | ++++++++++ help: consider specifying the type arguments in the function call | LL | test::<T, U>(22, std::default::Default::default()); diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr index c18abf95083da..b29442d7b8fb2 100644 --- a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `Qux` in the current scop --> $DIR/explicitly-unimplemented-error-message.rs:34:9 | LL | struct Qux; - | ----------- method `clone` not found for this + | ---------- method `clone` not found for this struct ... LL | Qux.clone(); | ^^^^^ method not found in `Qux` @@ -23,7 +23,7 @@ error[E0599]: no method named `foo` found for struct `Qux` in the current scope --> $DIR/explicitly-unimplemented-error-message.rs:44:9 | LL | struct Qux; - | ----------- method `foo` not found for this + | ---------- method `foo` not found for this struct ... LL | Qux.foo(); | ^^^ method not found in `Qux` diff --git a/src/test/ui/traits/object/with-self-in-projection-output-bad.stderr b/src/test/ui/traits/object/with-self-in-projection-output-bad.stderr index 45978a84068de..641bfe236660b 100644 --- a/src/test/ui/traits/object/with-self-in-projection-output-bad.stderr +++ b/src/test/ui/traits/object/with-self-in-projection-output-bad.stderr @@ -2,7 +2,7 @@ error[E0191]: the value of the associated type `Output` (from trait `Base`) must --> $DIR/with-self-in-projection-output-bad.rs:45:21 | LL | type Output; - | ------------ `Output` defined here + | ----------- `Output` defined here ... LL | let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32); | ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = Type>` @@ -11,7 +11,7 @@ error[E0191]: the value of the associated type `Output` (from trait `Base`) must --> $DIR/with-self-in-projection-output-bad.rs:48:21 | LL | type Output; - | ------------ `Output` defined here + | ----------- `Output` defined here ... LL | let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = Type>` diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr index 44f32e0cec91c..3985372119e88 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` | - = note: required for the cast to the object type `dyn Bar<_>` + = note: required for the cast from `&dyn Foo` to the object type `dyn Bar<_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr index 4ae4c8552c161..93c71f54eb53a 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied LL | let _ = x as &dyn Bar<u32>; // Error | ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>` | - = note: required for the cast to the object type `dyn Bar<u32>` + = note: required for the cast from `&dyn Foo<i32>` to the object type `dyn Bar<u32>` error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>` --> $DIR/type-checking-test-2.rs:26:13 @@ -34,7 +34,7 @@ error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied LL | let a = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>` | - = note: required for the cast to the object type `dyn Bar<_>` + = note: required for the cast from `&dyn Foo<u32>` to the object type `dyn Bar<_>` error: aborting due to 4 previous errors diff --git a/src/test/ui/traits/vtable/vtable-diamond.stderr b/src/test/ui/traits/vtable/vtable-diamond.stderr index f71bed84d5627..f3718c5d852f0 100644 --- a/src/test/ui/traits/vtable/vtable-diamond.stderr +++ b/src/test/ui/traits/vtable/vtable-diamond.stderr @@ -10,11 +10,8 @@ error: vtable entries for `<S as D>`: [ ] --> $DIR/vtable-diamond.rs:21:1 | -LL | / trait D: B + C { -LL | | -LL | | fn foo_d(&self) {} -LL | | } - | |_^ +LL | trait D: B + C { + | ^^^^^^^^^^^^^^ error: vtable entries for `<S as C>`: [ MetadataDropInPlace, @@ -25,11 +22,8 @@ error: vtable entries for `<S as C>`: [ ] --> $DIR/vtable-diamond.rs:15:1 | -LL | / trait C: A { -LL | | -LL | | fn foo_c(&self) {} -LL | | } - | |_^ +LL | trait C: A { + | ^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/vtable/vtable-multi-level.stderr b/src/test/ui/traits/vtable/vtable-multi-level.stderr index 915fd701b0336..d4d7a8fa3a470 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.stderr +++ b/src/test/ui/traits/vtable/vtable-multi-level.stderr @@ -31,11 +31,8 @@ error: vtable entries for `<S as O>`: [ ] --> $DIR/vtable-multi-level.rs:95:1 | -LL | / trait O: G + N { -LL | | -LL | | fn foo_o(&self) {} -LL | | } - | |_^ +LL | trait O: G + N { + | ^^^^^^^^^^^^^^ error: vtable entries for `<S as B>`: [ MetadataDropInPlace, @@ -45,11 +42,8 @@ error: vtable entries for `<S as B>`: [ ] --> $DIR/vtable-multi-level.rs:19:1 | -LL | / trait B { -LL | | -LL | | fn foo_b(&self) {} -LL | | } - | |_^ +LL | trait B { + | ^^^^^^^ error: vtable entries for `<S as D>`: [ MetadataDropInPlace, @@ -59,11 +53,8 @@ error: vtable entries for `<S as D>`: [ ] --> $DIR/vtable-multi-level.rs:30:1 | -LL | / trait D { -LL | | -LL | | fn foo_d(&self) {} -LL | | } - | |_^ +LL | trait D { + | ^^^^^^^ error: vtable entries for `<S as E>`: [ MetadataDropInPlace, @@ -73,11 +64,8 @@ error: vtable entries for `<S as E>`: [ ] --> $DIR/vtable-multi-level.rs:36:1 | -LL | / trait E { -LL | | -LL | | fn foo_e(&self) {} -LL | | } - | |_^ +LL | trait E { + | ^^^^^^^ error: vtable entries for `<S as F>`: [ MetadataDropInPlace, @@ -90,11 +78,8 @@ error: vtable entries for `<S as F>`: [ ] --> $DIR/vtable-multi-level.rs:42:1 | -LL | / trait F: D + E { -LL | | -LL | | fn foo_f(&self) {} -LL | | } - | |_^ +LL | trait F: D + E { + | ^^^^^^^^^^^^^^ error: vtable entries for `<S as H>`: [ MetadataDropInPlace, @@ -104,11 +89,8 @@ error: vtable entries for `<S as H>`: [ ] --> $DIR/vtable-multi-level.rs:53:1 | -LL | / trait H { -LL | | -LL | | fn foo_h(&self) {} -LL | | } - | |_^ +LL | trait H { + | ^^^^^^^ error: vtable entries for `<S as I>`: [ MetadataDropInPlace, @@ -118,11 +100,8 @@ error: vtable entries for `<S as I>`: [ ] --> $DIR/vtable-multi-level.rs:59:1 | -LL | / trait I { -LL | | -LL | | fn foo_i(&self) {} -LL | | } - | |_^ +LL | trait I { + | ^^^^^^^ error: vtable entries for `<S as J>`: [ MetadataDropInPlace, @@ -135,11 +114,8 @@ error: vtable entries for `<S as J>`: [ ] --> $DIR/vtable-multi-level.rs:65:1 | -LL | / trait J: H + I { -LL | | -LL | | fn foo_j(&self) {} -LL | | } - | |_^ +LL | trait J: H + I { + | ^^^^^^^^^^^^^^ error: vtable entries for `<S as K>`: [ MetadataDropInPlace, @@ -149,11 +125,8 @@ error: vtable entries for `<S as K>`: [ ] --> $DIR/vtable-multi-level.rs:71:1 | -LL | / trait K { -LL | | -LL | | fn foo_k(&self) {} -LL | | } - | |_^ +LL | trait K { + | ^^^^^^^ error: vtable entries for `<S as L>`: [ MetadataDropInPlace, @@ -163,11 +136,8 @@ error: vtable entries for `<S as L>`: [ ] --> $DIR/vtable-multi-level.rs:77:1 | -LL | / trait L { -LL | | -LL | | fn foo_l(&self) {} -LL | | } - | |_^ +LL | trait L { + | ^^^^^^^ error: vtable entries for `<S as M>`: [ MetadataDropInPlace, @@ -180,11 +150,8 @@ error: vtable entries for `<S as M>`: [ ] --> $DIR/vtable-multi-level.rs:83:1 | -LL | / trait M: K + L { -LL | | -LL | | fn foo_m(&self) {} -LL | | } - | |_^ +LL | trait M: K + L { + | ^^^^^^^^^^^^^^ error: vtable entries for `<S as N>`: [ MetadataDropInPlace, @@ -204,11 +171,8 @@ error: vtable entries for `<S as N>`: [ ] --> $DIR/vtable-multi-level.rs:89:1 | -LL | / trait N: J + M { -LL | | -LL | | fn foo_n(&self) {} -LL | | } - | |_^ +LL | trait N: J + M { + | ^^^^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/src/test/ui/traits/vtable/vtable-multiple.stderr b/src/test/ui/traits/vtable/vtable-multiple.stderr index f1c8947f9069f..0dcd84433090c 100644 --- a/src/test/ui/traits/vtable/vtable-multiple.stderr +++ b/src/test/ui/traits/vtable/vtable-multiple.stderr @@ -9,11 +9,8 @@ error: vtable entries for `<S as C>`: [ ] --> $DIR/vtable-multiple.rs:16:1 | -LL | / trait C: A + B { -LL | | -LL | | fn foo_c(&self) {} -LL | | } - | |_^ +LL | trait C: A + B { + | ^^^^^^^^^^^^^^ error: vtable entries for `<S as B>`: [ MetadataDropInPlace, @@ -23,11 +20,8 @@ error: vtable entries for `<S as B>`: [ ] --> $DIR/vtable-multiple.rs:10:1 | -LL | / trait B { -LL | | -LL | | fn foo_b(&self) {} -LL | | } - | |_^ +LL | trait B { + | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/vtable/vtable-non-object-safe.stderr b/src/test/ui/traits/vtable/vtable-non-object-safe.stderr index bbfbde222f334..9345c2711978a 100644 --- a/src/test/ui/traits/vtable/vtable-non-object-safe.stderr +++ b/src/test/ui/traits/vtable/vtable-non-object-safe.stderr @@ -10,7 +10,7 @@ error: vtable entries for `<std::vec::IntoIter<u8> as A>`: [ --> $DIR/vtable-non-object-safe.rs:8:1 | LL | trait A: Iterator {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/vtable/vtable-vacant.stderr b/src/test/ui/traits/vtable/vtable-vacant.stderr index c8cf58399723c..5346a70271635 100644 --- a/src/test/ui/traits/vtable/vtable-vacant.stderr +++ b/src/test/ui/traits/vtable/vtable-vacant.stderr @@ -9,12 +9,8 @@ error: vtable entries for `<S as B>`: [ ] --> $DIR/vtable-vacant.rs:15:1 | -LL | / trait B: A { -LL | | -LL | | fn foo_b1(&self) {} -LL | | fn foo_b2(&self) where Self: Send {} -LL | | } - | |_^ +LL | trait B: A { + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-opt-init.rs b/src/test/ui/try-block/try-block-opt-init.rs index ef10b47fd1305..f4f45abcc75b1 100644 --- a/src/test/ui/try-block/try-block-opt-init.rs +++ b/src/test/ui/try-block/try-block-opt-init.rs @@ -12,5 +12,5 @@ pub fn main() { Ok::<(), ()>(())?; use_val(cfg_res); }; - assert_eq!(cfg_res, 5); //~ ERROR borrow of possibly-uninitialized variable: `cfg_res` + assert_eq!(cfg_res, 5); //~ ERROR E0381 } diff --git a/src/test/ui/try-block/try-block-opt-init.stderr b/src/test/ui/try-block/try-block-opt-init.stderr index bd145fd64e765..c397385017ff4 100644 --- a/src/test/ui/try-block/try-block-opt-init.stderr +++ b/src/test/ui/try-block/try-block-opt-init.stderr @@ -1,8 +1,14 @@ -error[E0381]: borrow of possibly-uninitialized variable: `cfg_res` +error[E0381]: used binding `cfg_res` is possibly-uninitialized --> $DIR/try-block-opt-init.rs:15:5 | +LL | let cfg_res; + | ------- binding declared here but left uninitialized +... +LL | cfg_res = 5; + | ----------- binding initialized here in some conditions +... LL | assert_eq!(cfg_res, 5); - | ^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `cfg_res` + | ^^^^^^^^^^^^^^^^^^^^^^ `cfg_res` used here but it is possibly-uninitialized | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/tuple/add-tuple-within-arguments.rs b/src/test/ui/tuple/add-tuple-within-arguments.rs new file mode 100644 index 0000000000000..089c703fda5c7 --- /dev/null +++ b/src/test/ui/tuple/add-tuple-within-arguments.rs @@ -0,0 +1,10 @@ +fn foo(s: &str, a: (i32, i32), s2: &str) {} + +fn bar(s: &str, a: (&str,), s2: &str) {} + +fn main() { + foo("hi", 1, 2, "hi"); + //~^ ERROR this function takes 3 arguments but 4 arguments were supplied + bar("hi", "hi", "hi"); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/tuple/add-tuple-within-arguments.stderr b/src/test/ui/tuple/add-tuple-within-arguments.stderr new file mode 100644 index 0000000000000..95df96ca0dd4f --- /dev/null +++ b/src/test/ui/tuple/add-tuple-within-arguments.stderr @@ -0,0 +1,40 @@ +error[E0061]: this function takes 3 arguments but 4 arguments were supplied + --> $DIR/add-tuple-within-arguments.rs:6:5 + | +LL | foo("hi", 1, 2, "hi"); + | ^^^ + | +note: function defined here + --> $DIR/add-tuple-within-arguments.rs:1:4 + | +LL | fn foo(s: &str, a: (i32, i32), s2: &str) {} + | ^^^ ------- ------------- -------- +help: wrap these arguments in parentheses to construct a tuple + | +LL | foo("hi", (1, 2), "hi"); + | + + + +error[E0308]: mismatched types + --> $DIR/add-tuple-within-arguments.rs:8:15 + | +LL | bar("hi", "hi", "hi"); + | --- ^^^^ expected tuple, found `&str` + | | + | arguments to this function are incorrect + | + = note: expected tuple `(&str,)` + found reference `&'static str` +note: function defined here + --> $DIR/add-tuple-within-arguments.rs:3:4 + | +LL | fn bar(s: &str, a: (&str,), s2: &str) {} + | ^^^ ------- ---------- -------- +help: use a trailing comma to create a tuple with one element + | +LL | bar("hi", ("hi",), "hi"); + | + ++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/tuple/wrong_argument_ice-2.stderr b/src/test/ui/tuple/wrong_argument_ice-2.stderr index c704ae9934b1c..0c2a4c41461fc 100644 --- a/src/test/ui/tuple/wrong_argument_ice-2.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-2.stderr @@ -9,7 +9,7 @@ note: function defined here | LL | fn test(t: (i32, i32)) {} | ^^^^ ------------- -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | test((x.qux(), x.qux())); | + + diff --git a/src/test/ui/tuple/wrong_argument_ice-3.stderr b/src/test/ui/tuple/wrong_argument_ice-3.stderr index 667b15776efd3..2733fb3149b55 100644 --- a/src/test/ui/tuple/wrong_argument_ice-3.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-3.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/wrong_argument_ice-3.rs:9:16 | LL | groups.push(new_group, vec![process]); - | ^^^^ --------- ------------- argument unexpected + | ^^^^ --------- ------------- argument of type `Vec<&Process>` unexpected | | | expected tuple, found struct `Vec` | diff --git a/src/test/ui/tuple/wrong_argument_ice-4.stderr b/src/test/ui/tuple/wrong_argument_ice-4.stderr index f8dfc4cd043cd..828ae21b4808d 100644 --- a/src/test/ui/tuple/wrong_argument_ice-4.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-4.stderr @@ -6,7 +6,7 @@ LL | (|| {})(|| { LL | | LL | | let b = 1; LL | | }); - | |_____- argument unexpected + | |_____- argument of type `[closure@$DIR/wrong_argument_ice-4.rs:2:13: 2:15]` unexpected | note: closure defined here --> $DIR/wrong_argument_ice-4.rs:2:6 diff --git a/src/test/ui/tuple/wrong_argument_ice.stderr b/src/test/ui/tuple/wrong_argument_ice.stderr index 2b4cb669f5c7d..ec07f1e70cff6 100644 --- a/src/test/ui/tuple/wrong_argument_ice.stderr +++ b/src/test/ui/tuple/wrong_argument_ice.stderr @@ -9,7 +9,7 @@ note: associated function defined here | LL | pub fn push_back(&mut self, value: T) { | ^^^^^^^^^ -help: use parentheses to construct a tuple +help: wrap these arguments in parentheses to construct a tuple | LL | self.acc.push_back((self.current_provides, self.current_requires)); | + + diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr index f007f71a73c45..aaa3159e0b047 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr @@ -16,7 +16,7 @@ note: `V` could also refer to the associated type defined here --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:26:5 | LL | type V; - | ^^^^^^^ + | ^^^^^^ error: ambiguous associated item --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:32:15 @@ -35,7 +35,7 @@ note: `V` could also refer to the associated type defined here --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:26:5 | LL | type V; - | ^^^^^^^ + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs index b456b1445e784..5fb7a9473d3df 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs @@ -6,7 +6,6 @@ mod m { type Foo = impl std::fmt::Debug; //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] - //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] pub fn foo() -> Foo { 22_u32 diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr index 4c44875b4a548..1e9a45aac79e9 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr @@ -5,10 +5,11 @@ LL | type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:5 + --> $DIR/auto-trait-leakage3.rs:15:9 | -LL | pub fn bar() { - | ^^^^^^^^^^^^ +LL | is_send(foo()); + | ^^^^^^^ + = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/auto-trait-leakage3.rs:6:1 @@ -16,24 +17,6 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:16 - | -LL | type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:5 - | -LL | pub fn bar() { - | ^^^^^^^^^^^^ - = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when checking item types in module `m` - --> $DIR/auto-trait-leakage3.rs:6:1 - | -LL | mod m { - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/closures_in_branches.rs b/src/test/ui/type-alias-impl-trait/closures_in_branches.rs index a1a9401acc2c4..7bb490bbec818 100644 --- a/src/test/ui/type-alias-impl-trait/closures_in_branches.rs +++ b/src/test/ui/type-alias-impl-trait/closures_in_branches.rs @@ -4,7 +4,7 @@ type Foo = impl std::ops::FnOnce(String) -> usize; fn foo(b: bool) -> Foo { if b { - |x| x.len() + |x| x.len() //~ ERROR type annotations needed } else { panic!() } diff --git a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr index b3ca260894bc8..48b7946ea820e 100644 --- a/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr +++ b/src/test/ui/type-alias-impl-trait/closures_in_branches.stderr @@ -1,15 +1,25 @@ +error[E0282]: type annotations needed + --> $DIR/closures_in_branches.rs:7:10 + | +LL | |x| x.len() + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | |x: _| x.len() + | +++ + error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:21:10 | LL | |x| x.len() - | ^ + | ^ - type must be known at this point | - = note: type must be known at this point help: consider giving this closure parameter an explicit type | LL | |x: _| x.len() | +++ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs index 811832848d9dd..9a50c0f988a56 100644 --- a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs +++ b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs @@ -1,8 +1,9 @@ // compile-flags: --edition=2021 +// check-pass #![feature(type_alias_impl_trait)] fn main() { - type T = impl Copy; //~ ERROR unconstrained opaque type + type T = impl Copy; let foo: T = (1u32, 2u32); let (a, b): (u32, u32) = foo; } diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr deleted file mode 100644 index 03b172e6de570..0000000000000 --- a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unconstrained opaque type - --> $DIR/cross_inference_pattern_bug.rs:5:14 - | -LL | type T = impl Copy; - | ^^^^^^^^^ - | - = note: `T` must be used in combination with a concrete type within the same module - -error: aborting due to previous error - diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs index 179f525de52b0..b929122a6c23f 100644 --- a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs +++ b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs @@ -1,13 +1,13 @@ -// known-bug // compile-flags: --edition=2021 --crate-type=lib // rustc-env:RUST_BACKTRACE=0 +// check-pass // tracked in https://github.com/rust-lang/rust/issues/96572 #![feature(type_alias_impl_trait)] fn main() { - type T = impl Copy; // error: unconstrained opaque type + type T = impl Copy; let foo: T = (1u32, 2u32); - let (a, b) = foo; // removing this line makes the code compile + let (a, b) = foo; // this line used to make the code fail } diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr deleted file mode 100644 index 8aa1f49563995..0000000000000 --- a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unconstrained opaque type - --> $DIR/cross_inference_pattern_bug_no_type.rs:10:14 - | -LL | type T = impl Copy; // error: unconstrained opaque type - | ^^^^^^^^^ - | - = note: `T` must be used in combination with a concrete type within the same module - -error: aborting due to previous error - diff --git a/src/test/ui/type-alias-impl-trait/fallback.rs b/src/test/ui/type-alias-impl-trait/fallback.rs index d7e93335f47fa..d8cf7d71fef74 100644 --- a/src/test/ui/type-alias-impl-trait/fallback.rs +++ b/src/test/ui/type-alias-impl-trait/fallback.rs @@ -1,7 +1,6 @@ // Tests that we correctly handle opaque types being used opaquely, // even within their defining scope. // -// check-pass #![feature(type_alias_impl_trait)] type Foo = impl Copy; @@ -23,6 +22,7 @@ fn constrained_foo() -> Foo { // constraints on it. fn unconstrained_foo() -> Wrapper<Foo> { Wrapper::Second + //~^ ERROR: type annotations needed } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/fallback.stderr b/src/test/ui/type-alias-impl-trait/fallback.stderr new file mode 100644 index 0000000000000..e767bfdb08b6b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/fallback.stderr @@ -0,0 +1,17 @@ +error[E0283]: type annotations needed + --> $DIR/fallback.rs:24:5 + | +LL | fn unconstrained_foo() -> Wrapper<Foo> { + | ------------ type must be known at this point +LL | Wrapper::Second + | ^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the enum `Wrapper` + | + = note: cannot satisfy `_: Copy` +help: consider specifying the generic argument + | +LL | Wrapper::<T>::Second + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.rs b/src/test/ui/type-alias-impl-trait/inference-cycle.rs index 608572978a351..79caddf791320 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.rs +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.rs @@ -4,7 +4,6 @@ mod m { type Foo = impl std::fmt::Debug; //~^ ERROR cycle detected - //~| ERROR cycle detected // Cycle: error today, but it'd be nice if it eventually worked diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr index 3ed86fae8a18d..b9d646b927a6f 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr @@ -5,10 +5,11 @@ LL | type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:5 + --> $DIR/inference-cycle.rs:15:9 | -LL | pub fn bar() { - | ^^^^^^^^^^^^ +LL | is_send(foo()); // Today: error + | ^^^^^^^ + = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/inference-cycle.rs:4:1 @@ -16,24 +17,6 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:16 - | -LL | type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:5 - | -LL | pub fn bar() { - | ^^^^^^^^^^^^ - = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when checking item types in module `m` - --> $DIR/inference-cycle.rs:4:1 - | -LL | mod m { - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr index f4a0cdb1625b8..1b89d55711dbd 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -8,7 +8,7 @@ note: ...which requires type-checking `CONST_BUG`... --> $DIR/issue-53092-2.rs:6:1 | LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Bug<u8, ()>`... = note: ...which requires normalizing `Bug<u8, ()>`... = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle @@ -30,7 +30,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:71]` (0 bits) + = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:68]` (0 bits) = note: target type: `Bug<u8, ()>` (size can vary because of [type error]) error[E0277]: the trait bound `U: From<T>` is not satisfied diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs index 6c838f410036a..377ce85e8b221 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs @@ -3,7 +3,8 @@ type Foo = impl Fn() -> Foo; fn foo() -> Foo { - foo //~ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` +//~^ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` + foo } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr index a9c2c18630c01..d20b1cc6d851b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized` - --> $DIR/issue-53398-cyclic-types.rs:6:5 + --> $DIR/issue-53398-cyclic-types.rs:5:13 | -LL | foo - | ^^^ +LL | fn foo() -> Foo { + | ^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`) diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 9c4e6c5496fb7..067ed7ea1e585 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -1,7 +1,7 @@ // Regression test for issue #57611 // Ensures that we don't ICE // FIXME: This should compile, but it currently doesn't -// known-bug +// known-bug: unknown #![feature(trait_alias)] #![feature(type_alias_impl_trait)] diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index ed1cf1852e76a..f14bf6b0f7f5c 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -10,7 +10,7 @@ note: this closure does not fulfill the lifetime requirements --> $DIR/issue-57611-trait-alias.rs:21:9 | LL | |x| x - | ^^^^^ + | ^^^ error: implementation of `FnOnce` is not general enough --> $DIR/issue-57611-trait-alias.rs:21:9 diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index d0c04371bd793..082b0f0c30973 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -11,7 +11,7 @@ error[E0277]: the trait bound `(): Bug` is not satisfied --> $DIR/issue-60371.rs:10:40 | LL | const FUN: fn() -> Self::Item = || (); - | ^^ the trait `Bug` is not implemented for `()` + | ^ the trait `Bug` is not implemented for `()` | = help: the trait `Bug` is implemented for `&()` diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.rs b/src/test/ui/type-alias-impl-trait/issue-63279.rs index 057a908bbee74..97332e16d84a2 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.rs +++ b/src/test/ui/type-alias-impl-trait/issue-63279.rs @@ -5,6 +5,7 @@ type Closure = impl FnOnce(); fn c() -> Closure { + //~^ ERROR: expected a `FnOnce<()>` closure, found `()` || -> Closure { || () } //~^ ERROR: mismatched types //~| ERROR: mismatched types diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index ab39ee74be442..110b8d1eea4d7 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -1,5 +1,14 @@ error[E0277]: expected a `FnOnce<()>` closure, found `()` - --> $DIR/issue-63279.rs:8:11 + --> $DIR/issue-63279.rs:7:11 + | +LL | fn c() -> Closure { + | ^^^^^^^ expected an `FnOnce<()>` closure, found `()` + | + = help: the trait `FnOnce<()>` is not implemented for `()` + = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` + +error[E0277]: expected a `FnOnce<()>` closure, found `()` + --> $DIR/issue-63279.rs:9:11 | LL | || -> Closure { || () } | ^^^^^^^ expected an `FnOnce<()>` closure, found `()` @@ -8,33 +17,32 @@ LL | || -> Closure { || () } = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` error[E0308]: mismatched types - --> $DIR/issue-63279.rs:8:21 + --> $DIR/issue-63279.rs:9:21 | LL | || -> Closure { || () } | ^^^^^ expected `()`, found closure | = note: expected unit type `()` - found closure `[closure@$DIR/issue-63279.rs:8:21: 8:26]` + found closure `[closure@$DIR/issue-63279.rs:9:21: 9:23]` help: use parentheses to call this closure | LL | || -> Closure { (|| ())() } | + +++ error[E0308]: mismatched types - --> $DIR/issue-63279.rs:8:5 + --> $DIR/issue-63279.rs:9:5 | -LL | type Closure = impl FnOnce(); - | ------------- the expected opaque type -LL | -LL | fn c() -> Closure { - | ------- expected `Closure` because of return type LL | || -> Closure { || () } | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found closure | - = note: expected opaque type `Closure` - found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]` + = note: expected unit type `()` + found closure `[closure@$DIR/issue-63279.rs:9:5: 9:18]` +help: use parentheses to call this closure + | +LL | (|| -> Closure { || () })() + | + +++ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-72793.rs b/src/test/ui/type-alias-impl-trait/issue-72793.rs new file mode 100644 index 0000000000000..828c871143ad5 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-72793.rs @@ -0,0 +1,25 @@ +// check-pass +// compile-flags: -Zmir-opt-level=3 + +#![feature(type_alias_impl_trait)] + +trait T { type Item; } + +type Alias<'a> = impl T<Item = &'a ()>; + +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} + +fn filter_positive<'a>() -> Alias<'a> { + &S +} + +fn with_positive(fun: impl Fn(Alias<'_>)) { + fun(filter_positive()); +} + +fn main() { + with_positive(|_| ()); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.stderr b/src/test/ui/type-alias-impl-trait/issue-74280.stderr index 573e691b4cc07..5ed29e0ac94ff 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74280.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74280.stderr @@ -1,17 +1,11 @@ error[E0308]: mismatched types --> $DIR/issue-74280.rs:9:5 | -LL | type Test = impl Copy; - | --------- the expected opaque type -LL | LL | fn test() -> Test { - | ---- expected `Test` because of return type + | ---- expected `_` because of return type LL | let y = || -> Test { () }; LL | 7 | ^ expected `()`, found integer - | - = note: expected opaque type `Test` - found type `{integer}` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-94429.rs b/src/test/ui/type-alias-impl-trait/issue-94429.rs index 51d69c1271e02..2c965b875a00b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-94429.rs +++ b/src/test/ui/type-alias-impl-trait/issue-94429.rs @@ -13,7 +13,8 @@ impl Runnable for Implementor { type Gen = impl Generator<Yield = (), Return = ()>; fn run(&mut self) -> Self::Gen { - move || { //~ ERROR: type mismatch resolving + //~^ ERROR: type mismatch resolving + move || { yield 1; } } diff --git a/src/test/ui/type-alias-impl-trait/issue-94429.stderr b/src/test/ui/type-alias-impl-trait/issue-94429.stderr index 4546f82b83b85..8d7f7a07b60c7 100644 --- a/src/test/ui/type-alias-impl-trait/issue-94429.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-94429.stderr @@ -1,10 +1,8 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/issue-94429.rs:16:9: 18:10] as Generator>::Yield == ()` - --> $DIR/issue-94429.rs:16:9 +error[E0271]: type mismatch resolving `<[generator@$DIR/issue-94429.rs:17:9: 17:16] as Generator>::Yield == ()` + --> $DIR/issue-94429.rs:15:26 | -LL | / move || { -LL | | yield 1; -LL | | } - | |_________^ expected integer, found `()` +LL | fn run(&mut self) -> Self::Gen { + | ^^^^^^^^^ expected integer, found `()` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs new file mode 100644 index 0000000000000..825710851b01f --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +fn main() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + match foo { + None => (), + Some((a, b, c)) => (), //~ ERROR mismatched types + } +} diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr new file mode 100644 index 0000000000000..728244a1844db --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-96572-unconstrained-mismatch.rs:8:14 + | +LL | match foo { + | --- this expression has type `T` +LL | None => (), +LL | Some((a, b, c)) => (), + | ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements + | + = note: expected tuple `(u32, u32)` + found tuple `(_, _, _)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs new file mode 100644 index 0000000000000..c0a371eca1c6f --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern-rpit.rs @@ -0,0 +1,29 @@ +// check-pass + +#[allow(unconditional_recursion)] +fn foo(b: bool) -> impl Copy { + let (mut x, mut y) = foo(false); + x = 42; + y = "foo"; + if b { + panic!() + } else { + foo(true) + } +} + +fn bar(b: bool) -> Option<impl Copy> { + if b { + return None; + } + match bar(!b) { + Some((mut x, mut y)) => { + x = 42; + y = "foo"; + } + None => {} + } + None +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs new file mode 100644 index 0000000000000..ec249958590f1 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-only-pattern.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +type T = impl Copy; + +fn foo(foo: T) { + let (mut x, mut y) = foo; + x = 42; + y = "foo"; +} + +type U = impl Copy; + +fn bar(bar: Option<U>) { + match bar { + Some((mut x, mut y)) => { + x = 42; + y = "foo"; + } + None => {} + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs new file mode 100644 index 0000000000000..3351d9bcff1f8 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-struct.rs @@ -0,0 +1,11 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +#[derive(Copy, Clone)] +struct Foo((u32, u32)); + +fn main() { + type U = impl Copy; + let foo: U = Foo((1u32, 2u32)); + let Foo((a, b)) = foo; +} diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs new file mode 100644 index 0000000000000..ef3279a98d199 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar-enum.rs @@ -0,0 +1,13 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +fn main() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + let x = move || { + match foo { + None => (), + Some((a, b)) => (), + } + }; +} diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs new file mode 100644 index 0000000000000..bb0fc7c7534f5 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained-upvar.rs @@ -0,0 +1,13 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +#[derive(Copy, Clone)] +struct Foo((u32, u32)); + +fn main() { + type T = impl Copy; + let foo: T = Foo((1u32, 2u32)); + let x = move || { + let Foo((a, b)) = foo; + }; +} diff --git a/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs new file mode 100644 index 0000000000000..4b9ed7f28eb3f --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-96572-unconstrained.rs @@ -0,0 +1,11 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +fn main() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + match foo { + None => (), + Some((a, b)) => (), + } +} diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.rs b/src/test/ui/type-alias-impl-trait/issue-98604.rs new file mode 100644 index 0000000000000..a4fd8a82a04fd --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98604.rs @@ -0,0 +1,13 @@ +// edition:2018 + +type AsyncFnPtr = Box< + dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>, +>; + +async fn test() {} + +#[allow(unused_must_use)] +fn main() { + Box::new(test) as AsyncFnPtr; + //~^ ERROR type mismatch +} diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr new file mode 100644 index 0000000000000..f04d1b4d7877e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr @@ -0,0 +1,18 @@ +error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>` + --> $DIR/issue-98604.rs:11:5 + | +LL | Box::new(test) as AsyncFnPtr; + | ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type + | +note: while checking the return type of the `async fn` + --> $DIR/issue-98604.rs:7:17 + | +LL | async fn test() {} + | ^ checked the `Output` of this `async fn`, found opaque type + = note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>` + found opaque type `impl Future<Output = ()>` + = note: required for the cast from `fn() -> impl Future<Output = ()> {test}` to the object type `dyn Fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.rs b/src/test/ui/type-alias-impl-trait/issue-98608.rs new file mode 100644 index 0000000000000..d75762a8b62f0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98608.rs @@ -0,0 +1,9 @@ +fn hi() -> impl Sized { std::ptr::null::<u8>() } + +fn main() { + let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); + //~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>` + let boxed = b(); + let null = *boxed; + println!("{null:?}"); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr new file mode 100644 index 0000000000000..8f3ec7d9d1616 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr @@ -0,0 +1,16 @@ +error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>` + --> $DIR/issue-98608.rs:4:39 + | +LL | fn hi() -> impl Sized { std::ptr::null::<u8>() } + | ---------- the found opaque type +... +LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); + | ^^^^^^^^^^^^ expected struct `Box`, found opaque type + | + = note: expected struct `Box<u8>` + found opaque type `impl Sized` + = note: required for the cast from `fn() -> impl Sized {hi}` to the object type `dyn Fn() -> Box<u8>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs index 46bac5a34f5c0..da845e86147b7 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs @@ -7,8 +7,8 @@ type X<A, B> = impl Into<&'static A>; fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) { - (a, a) //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied + (a, a) } fn main() { diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr index 198f3e26393d4..cdaae99e28621 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied - --> $DIR/multiple-def-uses-in-one-fn.rs:10:9 + --> $DIR/multiple-def-uses-in-one-fn.rs:9:45 | -LL | (a, a) - | ^ the trait `From<&A>` is not implemented for `&'static B` +LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) { + | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B` | = note: required because of the requirements on the impl of `Into<&'static B>` for `&A` help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr index db4b60461ef38..bbe709dccab4e 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 | -LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString; - | ------------- the expected opaque type -... LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) { | - - found type parameter | | @@ -11,8 +8,8 @@ LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A LL | (a, b) | ^ expected type parameter `A`, found type parameter `B` | - = note: expected opaque type `X<A, B>` - found type parameter `B` + = note: expected type parameter `A` + found type parameter `B` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr index 91c1d031e4e5e..c36b95f47e837 100644 --- a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr +++ b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `Assoc` not found for `V` --> $DIR/not_well_formed.rs:9:29 | LL | type Foo<V> = impl Trait<V::Assoc>; - | ^^^^^ associated type `Assoc` not found + | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.rs b/src/test/ui/type-alias-impl-trait/reveal_local.rs index 145186baa1faa..7ecb553530106 100644 --- a/src/test/ui/type-alias-impl-trait/reveal_local.rs +++ b/src/test/ui/type-alias-impl-trait/reveal_local.rs @@ -4,7 +4,6 @@ use std::fmt::Debug; type Foo = impl Debug; //~^ ERROR cycle detected -//~| ERROR cycle detected fn is_send<T: Send>() { } diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.stderr b/src/test/ui/type-alias-impl-trait/reveal_local.stderr index 5d48dd5b2bf73..27fded3332921 100644 --- a/src/test/ui/type-alias-impl-trait/reveal_local.stderr +++ b/src/test/ui/type-alias-impl-trait/reveal_local.stderr @@ -5,10 +5,11 @@ LL | type Foo = impl Debug; | ^^^^^^^^^^ | note: ...which requires type-checking `not_good`... - --> $DIR/reveal_local.rs:11:1 + --> $DIR/reveal_local.rs:13:5 | -LL | fn not_good() { - | ^^^^^^^^^^^^^ +LL | is_send::<Foo>(); + | ^^^^^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Send`... = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/reveal_local.rs:1:1 @@ -22,30 +23,6 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when computing type of `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `not_gooder`... - --> $DIR/reveal_local.rs:17:1 - | -LL | fn not_gooder() { - | ^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/reveal_local.rs:1:1 - | -LL | / #![feature(type_alias_impl_trait)] -LL | | -LL | | use std::fmt::Debug; -LL | | -... | -LL | | -LL | | fn main() {} - | |____________^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/self-referential-2.rs b/src/test/ui/type-alias-impl-trait/self-referential-2.rs index dc7054da5ec19..8781196c39fa1 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential-2.rs +++ b/src/test/ui/type-alias-impl-trait/self-referential-2.rs @@ -4,7 +4,7 @@ type Foo = impl std::fmt::Debug; type Bar = impl PartialEq<Foo>; fn bar() -> Bar { - 42_i32 //~ ERROR can't compare `i32` with `Foo` + 42_i32 //~^ ERROR can't compare `i32` with `Foo` } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/self-referential-2.stderr b/src/test/ui/type-alias-impl-trait/self-referential-2.stderr index 348696f25e3b5..2b505d30730a3 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential-2.stderr +++ b/src/test/ui/type-alias-impl-trait/self-referential-2.stderr @@ -1,8 +1,10 @@ error[E0277]: can't compare `i32` with `Foo` - --> $DIR/self-referential-2.rs:7:5 + --> $DIR/self-referential-2.rs:6:13 | +LL | fn bar() -> Bar { + | ^^^ no implementation for `i32 == Foo` LL | 42_i32 - | ^^^^^^ no implementation for `i32 == Foo` + | ------ return type was inferred to be `i32` here | = help: the trait `PartialEq<Foo>` is not implemented for `i32` = help: the following other types implement trait `PartialEq<Rhs>`: diff --git a/src/test/ui/type-alias-impl-trait/self-referential-4.rs b/src/test/ui/type-alias-impl-trait/self-referential-4.rs index 697ec56825a9c..36742c8ad57fc 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential-4.rs +++ b/src/test/ui/type-alias-impl-trait/self-referential-4.rs @@ -3,19 +3,19 @@ type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'static>> + std::fmt::Debug; fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { - i //~ ERROR can't compare `&i32` with `Bar<'b, 'static>` + i //~^ ERROR can't compare `&i32` with `Bar<'b, 'static>` } type Foo<'a, 'b> = impl PartialEq<Foo<'static, 'b>> + std::fmt::Debug; fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { - i //~ ERROR can't compare `&i32` with `Foo<'static, 'b>` + i //~^ ERROR can't compare `&i32` with `Foo<'static, 'b>` } type Moo<'a, 'b> = impl PartialEq<Moo<'static, 'a>> + std::fmt::Debug; fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> { - i //~ ERROR can't compare `&i32` with `Moo<'static, 'a>` + i //~^ ERROR can't compare `&i32` with `Moo<'static, 'a>` } fn main() { diff --git a/src/test/ui/type-alias-impl-trait/self-referential-4.stderr b/src/test/ui/type-alias-impl-trait/self-referential-4.stderr index 838264794194c..27880f792f462 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential-4.stderr +++ b/src/test/ui/type-alias-impl-trait/self-referential-4.stderr @@ -1,8 +1,10 @@ error[E0277]: can't compare `&i32` with `Bar<'b, 'static>` - --> $DIR/self-referential-4.rs:6:5 + --> $DIR/self-referential-4.rs:5:31 | +LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == Bar<'b, 'static>` LL | i - | ^ no implementation for `&i32 == Bar<'b, 'static>` + | - return type was inferred to be `&i32` here | = help: the trait `PartialEq<Bar<'b, 'static>>` is not implemented for `&i32` = help: the following other types implement trait `PartialEq<Rhs>`: @@ -17,10 +19,12 @@ LL | i and 6 others error[E0277]: can't compare `&i32` with `Foo<'static, 'b>` - --> $DIR/self-referential-4.rs:12:5 + --> $DIR/self-referential-4.rs:11:31 | +LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == Foo<'static, 'b>` LL | i - | ^ no implementation for `&i32 == Foo<'static, 'b>` + | - return type was inferred to be `&i32` here | = help: the trait `PartialEq<Foo<'static, 'b>>` is not implemented for `&i32` = help: the following other types implement trait `PartialEq<Rhs>`: @@ -35,10 +39,12 @@ LL | i and 6 others error[E0277]: can't compare `&i32` with `Moo<'static, 'a>` - --> $DIR/self-referential-4.rs:18:5 + --> $DIR/self-referential-4.rs:17:31 | +LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == Moo<'static, 'a>` LL | i - | ^ no implementation for `&i32 == Moo<'static, 'a>` + | - return type was inferred to be `&i32` here | = help: the trait `PartialEq<Moo<'static, 'a>>` is not implemented for `&i32` = help: the following other types implement trait `PartialEq<Rhs>`: diff --git a/src/test/ui/type-alias-impl-trait/self-referential.rs b/src/test/ui/type-alias-impl-trait/self-referential.rs index 4974ac72dad18..3ff5406a38270 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential.rs +++ b/src/test/ui/type-alias-impl-trait/self-referential.rs @@ -3,19 +3,22 @@ type Bar<'a, 'b> = impl PartialEq<Bar<'b, 'a>> + std::fmt::Debug; fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { - i //~ ERROR can't compare `&i32` with `Bar<'b, 'a>` + //~^ ERROR can't compare `&i32` with `Bar<'b, 'a>` + i } type Foo<'a, 'b> = (i32, impl PartialEq<Foo<'a, 'b>> + std::fmt::Debug); fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { - (42, i) //~ ERROR can't compare `&i32` with `(i32, &i32)` + //~^ ERROR can't compare `&i32` with `(i32, &i32)` + (42, i) } type Moo<'a, 'b> = (i32, impl PartialEq<Moo<'b, 'a>> + std::fmt::Debug); fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> { - (42, i) //~ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` + //~^ ERROR can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` + (42, i) } fn main() { diff --git a/src/test/ui/type-alias-impl-trait/self-referential.stderr b/src/test/ui/type-alias-impl-trait/self-referential.stderr index 2ebb15b880308..97d510f6830af 100644 --- a/src/test/ui/type-alias-impl-trait/self-referential.stderr +++ b/src/test/ui/type-alias-impl-trait/self-referential.stderr @@ -1,8 +1,11 @@ error[E0277]: can't compare `&i32` with `Bar<'b, 'a>` - --> $DIR/self-referential.rs:6:5 + --> $DIR/self-referential.rs:5:31 | +LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == Bar<'b, 'a>` +LL | LL | i - | ^ no implementation for `&i32 == Bar<'b, 'a>` + | - return type was inferred to be `&i32` here | = help: the trait `PartialEq<Bar<'b, 'a>>` is not implemented for `&i32` = help: the following other types implement trait `PartialEq<Rhs>`: @@ -17,10 +20,13 @@ LL | i and 6 others error[E0277]: can't compare `&i32` with `(i32, &i32)` - --> $DIR/self-referential.rs:12:10 + --> $DIR/self-referential.rs:12:31 | +LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == (i32, &i32)` +LL | LL | (42, i) - | ^ no implementation for `&i32 == (i32, &i32)` + | ------- return type was inferred to be `(i32, &i32)` here | = help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32` = help: the following other types implement trait `PartialEq<Rhs>`: @@ -35,10 +41,13 @@ LL | (42, i) and 6 others error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` - --> $DIR/self-referential.rs:18:10 + --> $DIR/self-referential.rs:19:31 | +LL | fn moo<'a, 'b>(i: &'a i32) -> Moo<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0})` +LL | LL | (42, i) - | ^ no implementation for `&i32 == (i32, Moo<'b, 'a>::{opaque#0})` + | ------- return type was inferred to be `(i32, &i32)` here | = help: the trait `PartialEq<(i32, Moo<'b, 'a>::{opaque#0})>` is not implemented for `&i32` = help: the following other types implement trait `PartialEq<Rhs>`: diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 7d7890c8b8097..4af4c22f75166 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -10,10 +10,6 @@ note: required by a bound in `foo` | LL | fn foo<T: Into<String>>(x: i32) {} | ^^^^^^^^^^^^ required by this bound in `foo` -help: consider specifying the generic argument - | -LL | foo::<T>(42); - | +++++ help: consider specifying the type argument in the function call | LL | foo::<T>(42); diff --git a/src/test/ui/type/type-ascription-instead-of-initializer.stderr b/src/test/ui/type/type-ascription-instead-of-initializer.stderr index 18ed4986f8931..fcac6c495c4b2 100644 --- a/src/test/ui/type/type-ascription-instead-of-initializer.stderr +++ b/src/test/ui/type/type-ascription-instead-of-initializer.stderr @@ -11,7 +11,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 | LL | let x: Vec::with_capacity(10, 20); - | ^^^^^^^^^^^^^^^^^^ -- argument unexpected + | ^^^^^^^^^^^^^^^^^^ -- argument of type `{integer}` unexpected | note: associated function defined here --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/src/test/ui/type/type-ascription-precedence.stderr b/src/test/ui/type/type-ascription-precedence.stderr index ebce257b278bb..a8139063db1d8 100644 --- a/src/test/ui/type/type-ascription-precedence.stderr +++ b/src/test/ui/type/type-ascription-precedence.stderr @@ -32,18 +32,12 @@ note: an implementation of `std::ops::Neg` might be missing for `Z` --> $DIR/type-ascription-precedence.rs:9:1 | LL | struct Z; - | ^^^^^^^^^ must implement `std::ops::Neg` + | ^^^^^^^^ must implement `std::ops::Neg` note: the following trait must be implemented --> $SRC_DIR/core/src/ops/arith.rs:LL:COL | -LL | / pub trait Neg { -LL | | /// The resulting type after applying the `-` operator. -LL | | #[stable(feature = "rust1", since = "1.0.0")] -LL | | type Output; -... | -LL | | fn neg(self) -> Self::Output; -LL | | } - | |_^ +LL | pub trait Neg { + | ^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:45:5 diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr index d68d5e5d40b9e..e823bad2668ae 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_array.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `[_; 0]` --> $DIR/cannot_infer_local_or_array.rs:2:9 | LL | let x = []; - | ^ + | ^ -- type must be known at this point | help: consider giving `x` an explicit type, where the placeholders `_` are specified | diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr index 6d1e490bcf330..75feb5698eb63 100644 --- a/src/test/ui/type/type-check/issue-40294.stderr +++ b/src/test/ui/type/type-check/issue-40294.stderr @@ -1,8 +1,8 @@ -error[E0283]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo` --> $DIR/issue-40294.rs:6:19 | LL | where &'a T : Foo, - | ^^^ cannot infer type for reference `&'a T` + | ^^^ | = note: cannot satisfy `&'a T: Foo` diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr index ea259cf3d3785..67a4745b399d6 100644 --- a/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr +++ b/src/test/ui/type/type-parameter-defaults-referencing-Self.stderr @@ -1,13 +1,11 @@ error[E0393]: the type parameter `T` must be explicitly specified --> $DIR/type-parameter-defaults-referencing-Self.rs:8:16 | -LL | / trait Foo<T=Self> { -LL | | fn method(&self); -LL | | } - | |_- type parameter `T` must be specified for this -LL | -LL | fn foo(x: &dyn Foo) { } - | ^^^ help: set the type parameter to the desired type: `Foo<T>` +LL | trait Foo<T=Self> { + | ----------------- type parameter `T` must be specified for this +... +LL | fn foo(x: &dyn Foo) { } + | ^^^ help: set the type parameter to the desired type: `Foo<T>` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/type/type-params-in-different-spaces-1.stderr b/src/test/ui/type/type-params-in-different-spaces-1.stderr index eeb09a9f02ea3..4e73e10a30143 100644 --- a/src/test/ui/type/type-params-in-different-spaces-1.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-1.stderr @@ -1,16 +1,12 @@ error[E0308]: mismatched types --> $DIR/type-params-in-different-spaces-1.rs:5:17 | -LL | / trait BrokenAdd: Copy + Add<Output=Self> { -LL | | fn broken_add<T>(&self, rhs: T) -> Self { - | | - found type parameter -LL | | *self + rhs - | | ^^^ expected type parameter `Self`, found type parameter `T` -LL | | -... | -LL | | } -LL | | } - | |_- expected type parameter +LL | trait BrokenAdd: Copy + Add<Output=Self> { + | ---------------------------------------- expected type parameter +LL | fn broken_add<T>(&self, rhs: T) -> Self { + | - found type parameter +LL | *self + rhs + | ^^^ expected type parameter `Self`, found type parameter `T` | = note: expected type parameter `Self` found type parameter `T` diff --git a/src/test/ui/type/type-params-in-different-spaces-3.stderr b/src/test/ui/type/type-params-in-different-spaces-3.stderr index 880c138d28762..c538d67316c6a 100644 --- a/src/test/ui/type/type-params-in-different-spaces-3.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-3.stderr @@ -1,16 +1,14 @@ error[E0308]: mismatched types --> $DIR/type-params-in-different-spaces-3.rs:3:9 | -LL | / trait Tr : Sized { -LL | | fn test<X>(u: X) -> Self { - | | - ---- expected `Self` because of return type - | | | - | | found type parameter -LL | | u - | | ^ expected type parameter `Self`, found type parameter `X` -LL | | } -LL | | } - | |_- expected type parameter +LL | trait Tr : Sized { + | ---------------- expected type parameter +LL | fn test<X>(u: X) -> Self { + | - ---- expected `Self` because of return type + | | + | found type parameter +LL | u + | ^ expected type parameter `Self`, found type parameter `X` | = note: expected type parameter `Self` found type parameter `X` diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr index 04392f7390dfc..3202710286e1a 100644 --- a/src/test/ui/type/type-recursive.stderr +++ b/src/test/ui/type/type-recursive.stderr @@ -42,9 +42,8 @@ error[E0072]: recursive type `T4` has infinite size --> $DIR/type-recursive.rs:16:1 | LL | struct T4(Option<T4>); - | ^^^^^^^^^^----------^^ - | | | - | | recursive without indirection + | ^^^^^^^^^ ---------- recursive without indirection + | | | recursive type has infinite size | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T4` representable diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index c1f3acbecf95f..ce6fdf811213f 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -1,8 +1,10 @@ // build-fail // error-pattern: reached the type-length limit while instantiating +// compile-flags: -Copt-level=0 // normalize-stderr-test: ".nll/" -> "/" // Test that the type length limit can be changed. +// The exact type depends on optimizations, so disable them. #![allow(dead_code)] #![type_length_limit="4"] diff --git a/src/test/ui/typeck/do-not-suggest-adding-missing-zero-to-floating-point-number.rs b/src/test/ui/typeck/do-not-suggest-adding-missing-zero-to-floating-point-number.rs new file mode 100644 index 0000000000000..501f4b6ef9ebc --- /dev/null +++ b/src/test/ui/typeck/do-not-suggest-adding-missing-zero-to-floating-point-number.rs @@ -0,0 +1,21 @@ +macro_rules! num { () => { 1 } } + +fn main() { + let x = 1i32; + x.e10; //~ERROR `i32` is a primitive type and therefore doesn't have fields + + let y = 1; + y.e10; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + + 2u32.e10; //~ERROR `u32` is a primitive type and therefore doesn't have fields + + num!().e10; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + + 2.e10foo; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + + 42._; + //~^ERROR expected identifier, found reserved identifier `_` + //~|ERROR `{integer}` is a primitive type and therefore doesn't have fields + + 42.a; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields +} diff --git a/src/test/ui/typeck/do-not-suggest-adding-missing-zero-to-floating-point-number.stderr b/src/test/ui/typeck/do-not-suggest-adding-missing-zero-to-floating-point-number.stderr new file mode 100644 index 0000000000000..1ef1d4c28e479 --- /dev/null +++ b/src/test/ui/typeck/do-not-suggest-adding-missing-zero-to-floating-point-number.stderr @@ -0,0 +1,51 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:16:8 + | +LL | 42._; + | ^ expected identifier, found reserved identifier + +error[E0610]: `i32` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:5:7 + | +LL | x.e10; + | ^^^ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:8:7 + | +LL | y.e10; + | ^^^ + +error[E0610]: `u32` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:10:10 + | +LL | 2u32.e10; + | ^^^ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:12:12 + | +LL | num!().e10; + | ^^^ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:14:7 + | +LL | 2.e10foo; + | ^^^^^^ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:16:8 + | +LL | 42._; + | ^ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/do-not-suggest-adding-missing-zero-to-floating-point-number.rs:20:8 + | +LL | 42.a; + | ^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0610`. diff --git a/src/test/ui/typeck/issue-65611.stderr b/src/test/ui/typeck/issue-65611.stderr index 5f831291a3851..003c630790d2c 100644 --- a/src/test/ui/typeck/issue-65611.stderr +++ b/src/test/ui/typeck/issue-65611.stderr @@ -3,8 +3,6 @@ error[E0282]: type annotations needed | LL | let x = buffer.last().unwrap().0.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` - | - = note: type must be known at this point error[E0609]: no field `0` on type `&_` --> $DIR/issue-65611.rs:59:36 diff --git a/src/test/ui/typeck/issue-91334.stderr b/src/test/ui/typeck/issue-91334.stderr index 633c7b11aa2f8..8508f7a38e239 100644 --- a/src/test/ui/typeck/issue-91334.stderr +++ b/src/test/ui/typeck/issue-91334.stderr @@ -43,7 +43,7 @@ LL | fn f(){||yield(((){), | help: a return type might be missing here: `-> _` | = note: expected unit type `()` - found generator `[generator@$DIR/issue-91334.rs:10:8: 10:23]` + found generator `[generator@$DIR/issue-91334.rs:10:8: 10:10]` error: aborting due to 5 previous errors diff --git a/src/test/ui/typeck/issue-98260.rs b/src/test/ui/typeck/issue-98260.rs new file mode 100644 index 0000000000000..cf48294e1997f --- /dev/null +++ b/src/test/ui/typeck/issue-98260.rs @@ -0,0 +1,9 @@ +fn main() {} +trait A { + fn a(aa: B) -> Result<_, B> { + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types [E0121] + Ok(()) + } +} + +enum B {} diff --git a/src/test/ui/typeck/issue-98260.stderr b/src/test/ui/typeck/issue-98260.stderr new file mode 100644 index 0000000000000..08a1d17e244a8 --- /dev/null +++ b/src/test/ui/typeck/issue-98260.stderr @@ -0,0 +1,12 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/issue-98260.rs:3:27 + | +LL | fn a(aa: B) -> Result<_, B> { + | -------^---- + | | | + | | not allowed in type signatures + | help: replace with the correct return type: `Result<(), B>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/typeck/point-at-type-parameter-definition.rs b/src/test/ui/typeck/point-at-type-parameter-definition.rs new file mode 100644 index 0000000000000..856c0db08f79c --- /dev/null +++ b/src/test/ui/typeck/point-at-type-parameter-definition.rs @@ -0,0 +1,17 @@ +trait Trait { + fn do_stuff(&self); +} + +struct Hello; + +impl Hello { + fn method(&self) {} +} + +impl<Hello> Trait for Vec<Hello> { + fn do_stuff(&self) { + self[0].method(); //~ ERROR no method named `method` found for type parameter `Hello` in the current scope + } +} + +fn main() {} diff --git a/src/test/ui/typeck/point-at-type-parameter-definition.stderr b/src/test/ui/typeck/point-at-type-parameter-definition.stderr new file mode 100644 index 0000000000000..8a6ab61100d24 --- /dev/null +++ b/src/test/ui/typeck/point-at-type-parameter-definition.stderr @@ -0,0 +1,12 @@ +error[E0599]: no method named `method` found for type parameter `Hello` in the current scope + --> $DIR/point-at-type-parameter-definition.rs:13:17 + | +LL | impl<Hello> Trait for Vec<Hello> { + | ----- method `method` not found for this type parameter +LL | fn do_stuff(&self) { +LL | self[0].method(); + | ^^^^^^ method not found in `Hello` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/typeck/remove-extra-argument.stderr b/src/test/ui/typeck/remove-extra-argument.stderr index 815297765c18c..703032a832231 100644 --- a/src/test/ui/typeck/remove-extra-argument.stderr +++ b/src/test/ui/typeck/remove-extra-argument.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/remove-extra-argument.rs:6:5 | LL | l(vec![], vec![]) - | ^ ------ argument unexpected + | ^ ------ argument of type `Vec<_>` unexpected | note: function defined here --> $DIR/remove-extra-argument.rs:3:4 diff --git a/src/test/ui/typeck/return_type_containing_closure.stderr b/src/test/ui/typeck/return_type_containing_closure.stderr index ae72b1477c885..101aee39559c3 100644 --- a/src/test/ui/typeck/return_type_containing_closure.stderr +++ b/src/test/ui/typeck/return_type_containing_closure.stderr @@ -5,7 +5,7 @@ LL | vec!['a'].iter().map(|c| c) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Map` | = note: expected unit type `()` - found struct `Map<std::slice::Iter<'_, char>, [closure@$DIR/return_type_containing_closure.rs:3:26: 3:31]>` + found struct `Map<std::slice::Iter<'_, char>, [closure@$DIR/return_type_containing_closure.rs:3:26: 3:29]>` help: consider using a semicolon here | LL | vec!['a'].iter().map(|c| c); diff --git a/src/test/ui/typeck/struct-enum-wrong-args.stderr b/src/test/ui/typeck/struct-enum-wrong-args.stderr index 2ea822df27509..f72082d530167 100644 --- a/src/test/ui/typeck/struct-enum-wrong-args.stderr +++ b/src/test/ui/typeck/struct-enum-wrong-args.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:6:13 | LL | let _ = Some(3, 2); - | ^^^^ - argument unexpected + | ^^^^ - argument of type `{integer}` unexpected | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -18,9 +18,9 @@ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:7:13 | LL | let _ = Ok(3, 6, 2); - | ^^ - - argument unexpected + | ^^ - - argument of type `{integer}` unexpected | | - | argument unexpected + | argument of type `{integer}` unexpected | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -68,7 +68,7 @@ error[E0061]: this struct takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:10:13 | LL | let _ = Wrapper(5, 2); - | ^^^^^^^ - argument unexpected + | ^^^^^^^ - argument of type `{integer}` unexpected | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:2:8 @@ -116,7 +116,7 @@ error[E0061]: this struct takes 2 arguments but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:13:13 | LL | let _ = DoubleWrapper(5, 2, 7); - | ^^^^^^^^^^^^^ - argument unexpected + | ^^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:3:8 diff --git a/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed new file mode 100644 index 0000000000000..ba83e79005b33 --- /dev/null +++ b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +fn main() { + 2.0e1; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.0E1; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.0f32; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.0f64; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.0e+12; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.0e-12; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.0e1f32; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields +} diff --git a/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs new file mode 100644 index 0000000000000..c102447f60288 --- /dev/null +++ b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.rs @@ -0,0 +1,11 @@ +// run-rustfix + +fn main() { + 2.e1; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.E1; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.f32; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.f64; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.e+12; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.e-12; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields + 2.e1f32; //~ERROR `{integer}` is a primitive type and therefore doesn't have fields +} diff --git a/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr new file mode 100644 index 0000000000000..e8e069708a864 --- /dev/null +++ b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr @@ -0,0 +1,80 @@ +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:4:7 + | +LL | 2.e1; + | ^^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0e1; + | + + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:5:7 + | +LL | 2.E1; + | ^^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0E1; + | + + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:6:7 + | +LL | 2.f32; + | ^^^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0f32; + | + + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:7:7 + | +LL | 2.f64; + | ^^^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0f64; + | + + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:8:7 + | +LL | 2.e+12; + | ^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0e+12; + | + + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:9:7 + | +LL | 2.e-12; + | ^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0e-12; + | + + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/suggest-adding-missing-zero-to-floating-point-number.rs:10:7 + | +LL | 2.e1f32; + | ^^^^^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period + | +LL | 2.0e1f32; + | + + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0610`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index 482d3e44fe4ea..bfa3061de0815 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -4,9 +4,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(|| drop(x)); - | --------^- - | | | - | | move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | | captured by this `Fn` closure error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure @@ -15,9 +14,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(|| drop(x)); - | --------^- - | | | - | | move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | | captured by this `FnMut` closure error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure @@ -26,9 +24,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(move || drop(x)); - | -------------^- - | | | - | | move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | | captured by this `Fn` closure error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure @@ -37,9 +34,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(move || drop(x)); - | -------------^- - | | | - | | move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | | captured by this `FnMut` closure error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index 666ab79b65c32..ff2a597bed065 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -3,8 +3,10 @@ error[E0282]: type annotations needed for `Option<T>` | LL | let mut closure0 = None; | ^^^^^^^^^^^^ +... +LL | return c(); + | --- type must be known at this point | - = note: type must be known at this point help: consider giving `closure0` an explicit type, where the placeholders `_` are specified | LL | let mut closure0: Option<T> = None; diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr index 68ec8d2ba8287..85ff49d61a3ff 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr @@ -2,9 +2,8 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closur --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13 | LL | let c = || drop(y.0); - | ^^^^^^^^---^ - | | | - | | closure is `FnOnce` because it moves the variable `y` out of its environment + | ^^ --- closure is `FnOnce` because it moves the variable `y` out of its environment + | | | this closure implements `FnOnce`, not `Fn` LL | foo(c); | --- the requirement to implement `Fn` derives from here diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr index 48ec620d92ea7..d6e74b5b8b914 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr @@ -28,17 +28,15 @@ LL | n += 1; error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure --> $DIR/unboxed-closures-mutate-upvar.rs:53:9 | -LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` ... -LL | let mut f = to_fn(move || { - | _________________-----_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | n += 1; - | | ^^^^^^ cannot assign -LL | | }); - | |_____- in this closure +LL | let mut f = to_fn(move || { + | ----- ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | n += 1; + | ^^^^^^ cannot assign error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr index 80e84fb7cad3f..7d15cd0c882a5 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr @@ -1,18 +1,15 @@ error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:11:9 | -LL | fn call<F>(f: F) where F : Fn() { - | - change this to accept `FnMut` instead of `Fn` +LL | fn call<F>(f: F) where F : Fn() { + | - change this to accept `FnMut` instead of `Fn` ... -LL | call(|| { - | _____----_- - | | | - | | expects `Fn` instead of `FnMut` -LL | | counter += 1; - | | ^^^^^^^^^^^^ cannot assign -LL | | -LL | | }); - | |_____- in this closure +LL | call(|| { + | ---- -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | counter += 1; + | ^^^^^^^^^^^^ cannot assign error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr index e9883903674ad..4f89afa320d70 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]` in the current scope +error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` in the current scope --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10 | LL | mut_.call((0, )); - | ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]` + | ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` | | | this is a function, perhaps you wish to call it diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs index b37ec2696de2f..2764bb563d307 100644 --- a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs +++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs @@ -25,5 +25,5 @@ fn main() { widget::Widget::new(); // Error. Widget type is not known to be uninhabited here, // so the following code is considered reachable. - *y = 2; //~ ERROR use of possibly-uninitialized variable + *y = 2; //~ ERROR E0381 } diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr index fb1953411685e..95c209f47c92a 100644 --- a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr +++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr @@ -1,8 +1,11 @@ -error[E0381]: use of possibly-uninitialized variable: `y` +error[E0381]: used binding `y` isn't initialized --> $DIR/privately-uninhabited-mir-call.rs:28:5 | +LL | let y: &mut u32; + | - binding declared here but left uninitialized +... LL | *y = 2; - | ^^^^^^ use of possibly-uninitialized `y` + | ^^^^^^ `y` used here but it isn't initialized error: aborting due to previous error diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr index 74216d265d034..2c107b1f7a47b 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -7,15 +7,11 @@ LL | let _ = match x { note: `Result<u32, &Void>` defined here --> $SRC_DIR/core/src/result.rs:LL:COL | -LL | / pub enum Result<T, E> { -LL | | /// Contains the success value -LL | | #[lang = "Ok"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E), - | | ^^^ not covered -LL | | } - | |_- +LL | pub enum Result<T, E> { + | --------------------- +... +LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E), + | ^^^ not covered = note: the matched value is of type `Result<u32, &Void>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -93,15 +89,11 @@ LL | let _ = match x { note: `Result<u32, Void>` defined here --> $SRC_DIR/core/src/result.rs:LL:COL | -LL | / pub enum Result<T, E> { -LL | | /// Contains the success value -LL | | #[lang = "Ok"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E), - | | ^^^ not covered -LL | | } - | |_- +LL | pub enum Result<T, E> { + | --------------------- +... +LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E), + | ^^^ not covered = note: the matched value is of type `Result<u32, Void>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -120,15 +112,11 @@ LL | let Ok(x) = x; note: `Result<u32, Void>` defined here --> $SRC_DIR/core/src/result.rs:LL:COL | -LL | / pub enum Result<T, E> { -LL | | /// Contains the success value -LL | | #[lang = "Ok"] -LL | | #[stable(feature = "rust1", since = "1.0.0")] -... | -LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E), - | | ^^^ not covered -LL | | } - | |_- +LL | pub enum Result<T, E> { + | --------------------- +... +LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E), + | ^^^ not covered = note: the matched value is of type `Result<u32, Void>` help: you might want to use `if let` to ignore the variant that isn't matched | diff --git a/src/test/ui/union/field_checks.rs b/src/test/ui/union/field_checks.rs new file mode 100644 index 0000000000000..d5d1e44ac855c --- /dev/null +++ b/src/test/ui/union/field_checks.rs @@ -0,0 +1,65 @@ +use std::mem::ManuallyDrop; + +union U1 { // OK + a: u8, +} + +union U2<T: Copy> { // OK + a: T, +} + +union U22<T> { // OK + a: ManuallyDrop<T>, +} + +union U23<T> { // OK + a: (ManuallyDrop<T>, i32), +} + +union U24<T> { // OK + a: [ManuallyDrop<T>; 2], +} + +union U3 { + a: String, //~ ERROR unions cannot contain fields that may need dropping +} + +union U32 { // field that does not drop but is not `Copy`, either + a: std::cell::RefCell<i32>, //~ ERROR unions cannot contain fields that may need dropping +} + +union U4<T> { + a: T, //~ ERROR unions cannot contain fields that may need dropping +} + +union U5 { // Having a drop impl is OK + a: u8, +} + +impl Drop for U5 { + fn drop(&mut self) {} +} + +union U5Nested { // a nested union that drops is NOT OK + nest: U5, //~ ERROR unions cannot contain fields that may need dropping +} + +union U5Nested2 { // for now we don't special-case empty arrays + nest: [U5; 0], //~ ERROR unions cannot contain fields that may need dropping +} + +union U6 { // OK + s: &'static i32, + m: &'static mut i32, +} + +union U7<T> { // OK + f: (&'static mut i32, ManuallyDrop<T>, i32), +} + +union U8<T> { // OK + f1: [(&'static mut i32, i32); 8], + f2: [ManuallyDrop<T>; 2], +} + +fn main() {} diff --git a/src/test/ui/union/field_checks.stderr b/src/test/ui/union/field_checks.stderr new file mode 100644 index 0000000000000..1f97e97ac6ede --- /dev/null +++ b/src/test/ui/union/field_checks.stderr @@ -0,0 +1,63 @@ +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:24:5 + | +LL | a: String, + | ^^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | a: std::mem::ManuallyDrop<String>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:28:5 + | +LL | a: std::cell::RefCell<i32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | a: std::mem::ManuallyDrop<std::cell::RefCell<i32>>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:32:5 + | +LL | a: T, + | ^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | a: std::mem::ManuallyDrop<T>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:44:5 + | +LL | nest: U5, + | ^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | nest: std::mem::ManuallyDrop<U5>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:48:5 + | +LL | nest: [U5; 0], + | ^^^^^^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | nest: std::mem::ManuallyDrop<[U5; 0]>, + | +++++++++++++++++++++++ + + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs index 80474b807e7f3..4dfdc606bb409 100644 --- a/src/test/ui/union/issue-41073.rs +++ b/src/test/ui/union/issue-41073.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - union Test { a: A, //~ ERROR unions cannot contain fields that may need dropping b: B diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr index 7d4208b10da80..b3887fa0f90be 100644 --- a/src/test/ui/union/issue-41073.stderr +++ b/src/test/ui/union/issue-41073.stderr @@ -1,5 +1,5 @@ error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/issue-41073.rs:4:5 + --> $DIR/issue-41073.rs:2:5 | LL | a: A, | ^^^^ diff --git a/src/test/ui/union/issue-81199.stderr b/src/test/ui/union/issue-81199.stderr index f26bfe3a0b060..5bb98675361a0 100644 --- a/src/test/ui/union/issue-81199.stderr +++ b/src/test/ui/union/issue-81199.stderr @@ -1,28 +1,18 @@ -error[E0277]: the trait bound `T: Pointee` is not satisfied in `PtrComponents<T>` +error[E0277]: the trait bound `T: Pointee` is not satisfied --> $DIR/issue-81199.rs:5:17 | LL | components: PtrComponents<T>, - | ^^^^^^^^^^^^^^^^ within `PtrComponents<T>`, the trait `Pointee` is not implemented for `T` + | ^^^^^^^^^^^^^^^^ the trait `Pointee` is not implemented for `T` | -note: required because it appears within the type `PtrComponents<T>` - --> $DIR/issue-81199.rs:10:8 +note: required by a bound in `PtrComponents` + --> $DIR/issue-81199.rs:10:25 | LL | struct PtrComponents<T: Pointee + ?Sized> { - | ^^^^^^^^^^^^^ - = note: no field of a union may have a dynamically sized type - = help: change the field's type to have a statically known size + | ^^^^^^^ required by this bound in `PtrComponents` help: consider further restricting this bound | LL | union PtrRepr<T: ?Sized + Pointee> { | +++++++++ -help: borrowed types always have a statically known size - | -LL | components: &PtrComponents<T>, - | + -help: the `Box` type always has a statically known size and allocates its contents in the heap - | -LL | components: Box<PtrComponents<T>>, - | ++++ + error: aborting due to previous error diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr index e785a2ee7335d..ca02de4c61bb8 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr @@ -1,49 +1,69 @@ -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) --> $DIR/union-borrow-move-parent-sibling.rs:56:13 | -LL | let a = &mut u.x.0; - | ---------- mutable borrow occurs here (via `u.x.0`) +LL | let a = &mut (*u.x).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` + +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>` + --> $DIR/union-borrow-move-parent-sibling.rs:62:13 + | +LL | let a = u.x.0; + | ^^^^^ + | | + | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait + | help: consider borrowing here: `&u.x.0` error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:63:13 + --> $DIR/union-borrow-move-parent-sibling.rs:64:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.x.0; - | ----- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:69:13 +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) + --> $DIR/union-borrow-move-parent-sibling.rs:70:13 | -LL | let a = &mut (u.x.0).0; - | -------------- mutable borrow occurs here (via `u.x.0.0`) +LL | let a = &mut ((*u.x).0).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` -error[E0382]: use of moved value: `u` +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>` --> $DIR/union-borrow-move-parent-sibling.rs:76:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let a = (u.x.0).0; + | ^^^^^^^^^ + | | + | move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait + | help: consider borrowing here: `&(u.x.0).0` + +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:78:13 + | +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = (u.x.0).0; - | --------- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:82:13 + --> $DIR/union-borrow-move-parent-sibling.rs:84:13 | LL | let a = &mut *u.y; | --- mutable borrow occurs here (via `u.y`) @@ -54,7 +74,7 @@ LL | use_borrow(a); | = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0382, E0502. +Some errors have detailed explanations: E0382, E0502, E0507. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs index e56d87255dbaf..83781c5e55092 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.rs +++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs @@ -1,10 +1,10 @@ // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] #![allow(unused)] use std::ops::{Deref, DerefMut}; +use std::mem::ManuallyDrop; #[derive(Default)] struct MockBox<T> { @@ -44,47 +44,49 @@ impl<T> DerefMut for MockVec<T> { union U { - x: ((MockVec<u8>, MockVec<u8>), MockVec<u8>), - y: MockBox<MockVec<u8>>, + x: ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>, + y: ManuallyDrop<MockBox<MockVec<u8>>>, } fn use_borrow<T>(_: &T) {} unsafe fn parent_sibling_borrow() { - let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = &mut u.x.0; + let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = &mut (*u.x).0; let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn parent_sibling_move() { - let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = u.x.0; + let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = u.x.0; //~ERROR cannot move out of dereference + let a = u.x; let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn grandparent_sibling_borrow() { - let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = &mut (u.x.0).0; + let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = &mut ((*u.x).0).0; let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn grandparent_sibling_move() { - let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = (u.x.0).0; + let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = (u.x.0).0; //~ERROR cannot move out of dereference + let a = u.x; let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn deref_sibling_borrow() { - let mut u = U { y: MockBox::default() }; + let mut u = U { y: ManuallyDrop::new(MockBox::default()) }; let a = &mut *u.y; let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`) use_borrow(a); } unsafe fn deref_sibling_move() { - let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; + let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; // No way to test deref-move without Box in union // let a = *u.y; // let b = u.x; ERROR use of moved value: `u` diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr index e785a2ee7335d..ca02de4c61bb8 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr @@ -1,49 +1,69 @@ -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) --> $DIR/union-borrow-move-parent-sibling.rs:56:13 | -LL | let a = &mut u.x.0; - | ---------- mutable borrow occurs here (via `u.x.0`) +LL | let a = &mut (*u.x).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` + +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>` + --> $DIR/union-borrow-move-parent-sibling.rs:62:13 + | +LL | let a = u.x.0; + | ^^^^^ + | | + | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait + | help: consider borrowing here: `&u.x.0` error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:63:13 + --> $DIR/union-borrow-move-parent-sibling.rs:64:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.x.0; - | ----- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:69:13 +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) + --> $DIR/union-borrow-move-parent-sibling.rs:70:13 | -LL | let a = &mut (u.x.0).0; - | -------------- mutable borrow occurs here (via `u.x.0.0`) +LL | let a = &mut ((*u.x).0).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` -error[E0382]: use of moved value: `u` +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>` --> $DIR/union-borrow-move-parent-sibling.rs:76:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let a = (u.x.0).0; + | ^^^^^^^^^ + | | + | move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait + | help: consider borrowing here: `&(u.x.0).0` + +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:78:13 + | +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = (u.x.0).0; - | --------- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:82:13 + --> $DIR/union-borrow-move-parent-sibling.rs:84:13 | LL | let a = &mut *u.y; | --- mutable borrow occurs here (via `u.y`) @@ -54,7 +74,7 @@ LL | use_borrow(a); | = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0382, E0502. +Some errors have detailed explanations: E0382, E0502, E0507. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs deleted file mode 100644 index 4b333631ec0f7..0000000000000 --- a/src/test/ui/union/union-custom-drop.rs +++ /dev/null @@ -1,19 +0,0 @@ -// test for a union with a field that's a union with a manual impl Drop -// Ensures we do not treat all unions as not having any drop glue. - -#![feature(untagged_unions)] - -union Foo { - bar: Bar, //~ ERROR unions cannot contain fields that may need dropping -} - -union Bar { - a: i32, - b: u32, -} - -impl Drop for Bar { - fn drop(&mut self) {} -} - -fn main() {} diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr deleted file mode 100644 index b5579eeef0977..0000000000000 --- a/src/test/ui/union/union-custom-drop.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/union-custom-drop.rs:7:5 - | -LL | bar: Bar, - | ^^^^^^^^ - | - = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type -help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped - | -LL | bar: std::mem::ManuallyDrop<Bar>, - | +++++++++++++++++++++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/union-deref.mirunsafeck.stderr b/src/test/ui/union/union-deref.mirunsafeck.stderr index ff37e6fd9177a..be5e60ab88a59 100644 --- a/src/test/ui/union/union-deref.mirunsafeck.stderr +++ b/src/test/ui/union/union-deref.mirunsafeck.stderr @@ -1,5 +1,5 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:17:14 + --> $DIR/union-deref.rs:16:14 | LL | unsafe { u.f.0 = Vec::new() }; | ^^^ @@ -8,7 +8,7 @@ LL | unsafe { u.f.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:19:19 + --> $DIR/union-deref.rs:18:19 | LL | unsafe { &mut u.f.0 }; | ^^^ @@ -17,7 +17,7 @@ LL | unsafe { &mut u.f.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:21:14 + --> $DIR/union-deref.rs:20:14 | LL | unsafe { u.f.0.push(0) }; | ^^^ @@ -26,7 +26,7 @@ LL | unsafe { u.f.0.push(0) }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:25:14 + --> $DIR/union-deref.rs:24:14 | LL | unsafe { u.f.0.0 = Vec::new() }; | ^^^^^ @@ -35,7 +35,7 @@ LL | unsafe { u.f.0.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:27:19 + --> $DIR/union-deref.rs:26:19 | LL | unsafe { &mut u.f.0.0 }; | ^^^^^ @@ -44,7 +44,7 @@ LL | unsafe { &mut u.f.0.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:29:14 + --> $DIR/union-deref.rs:28:14 | LL | unsafe { u.f.0.0.push(0) }; | ^^^^^ diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs index 4bf2ba2f1bfce..5aa28d93f96ed 100644 --- a/src/test/ui/union/union-deref.rs +++ b/src/test/ui/union/union-deref.rs @@ -3,7 +3,6 @@ //! Test the part of RFC 2514 that is about not applying `DerefMut` coercions //! of union fields. -#![feature(untagged_unions)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/union/union-deref.thirunsafeck.stderr b/src/test/ui/union/union-deref.thirunsafeck.stderr index ff37e6fd9177a..be5e60ab88a59 100644 --- a/src/test/ui/union/union-deref.thirunsafeck.stderr +++ b/src/test/ui/union/union-deref.thirunsafeck.stderr @@ -1,5 +1,5 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:17:14 + --> $DIR/union-deref.rs:16:14 | LL | unsafe { u.f.0 = Vec::new() }; | ^^^ @@ -8,7 +8,7 @@ LL | unsafe { u.f.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:19:19 + --> $DIR/union-deref.rs:18:19 | LL | unsafe { &mut u.f.0 }; | ^^^ @@ -17,7 +17,7 @@ LL | unsafe { &mut u.f.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:21:14 + --> $DIR/union-deref.rs:20:14 | LL | unsafe { u.f.0.push(0) }; | ^^^ @@ -26,7 +26,7 @@ LL | unsafe { u.f.0.push(0) }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:25:14 + --> $DIR/union-deref.rs:24:14 | LL | unsafe { u.f.0.0 = Vec::new() }; | ^^^^^ @@ -35,7 +35,7 @@ LL | unsafe { u.f.0.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:27:19 + --> $DIR/union-deref.rs:26:19 | LL | unsafe { &mut u.f.0.0 }; | ^^^^^ @@ -44,7 +44,7 @@ LL | unsafe { &mut u.f.0.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:29:14 + --> $DIR/union-deref.rs:28:14 | LL | unsafe { u.f.0.0.push(0) }; | ^^^^^ diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr index c242a7de7abfb..148fb5046705b 100644 --- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr @@ -1,14 +1,31 @@ +error[E0277]: the trait bound `U1: Copy` is not satisfied + --> $DIR/union-derive-clone.rs:6:10 + | +LL | #[derive(Clone)] + | ^^^^^ the trait `Copy` is not implemented for `U1` + | +note: required by a bound in `AssertParamIsCopy` + --> $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> { + | ^^^^ required by this bound in `AssertParamIsCopy` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `U1` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied --> $DIR/union-derive-clone.rs:38:15 | LL | union U5<T> { | ----------- | | - | method `clone` not found for this + | method `clone` not found for this union | doesn't satisfy `U5<CloneNoCopy>: Clone` ... LL | struct CloneNoCopy; - | ------------------- doesn't satisfy `CloneNoCopy: Copy` + | ------------------ doesn't satisfy `CloneNoCopy: Copy` ... LL | let w = u.clone(); | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds @@ -26,23 +43,6 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` LL | #[derive(Clone, Copy)] | -error[E0277]: the trait bound `U1: Copy` is not satisfied - --> $DIR/union-derive-clone.rs:6:10 - | -LL | #[derive(Clone)] - | ^^^^^ the trait `Copy` is not implemented for `U1` - | -note: required by a bound in `AssertParamIsCopy` - --> $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> { - | ^^^^ required by this bound in `AssertParamIsCopy` - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider annotating `U1` with `#[derive(Copy)]` - | -LL | #[derive(Copy)] - | - error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0599. diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr index c242a7de7abfb..148fb5046705b 100644 --- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr @@ -1,14 +1,31 @@ +error[E0277]: the trait bound `U1: Copy` is not satisfied + --> $DIR/union-derive-clone.rs:6:10 + | +LL | #[derive(Clone)] + | ^^^^^ the trait `Copy` is not implemented for `U1` + | +note: required by a bound in `AssertParamIsCopy` + --> $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> { + | ^^^^ required by this bound in `AssertParamIsCopy` + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `U1` with `#[derive(Copy)]` + | +LL | #[derive(Copy)] + | + error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied --> $DIR/union-derive-clone.rs:38:15 | LL | union U5<T> { | ----------- | | - | method `clone` not found for this + | method `clone` not found for this union | doesn't satisfy `U5<CloneNoCopy>: Clone` ... LL | struct CloneNoCopy; - | ------------------- doesn't satisfy `CloneNoCopy: Copy` + | ------------------ doesn't satisfy `CloneNoCopy: Copy` ... LL | let w = u.clone(); | ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds @@ -26,23 +43,6 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` LL | #[derive(Clone, Copy)] | -error[E0277]: the trait bound `U1: Copy` is not satisfied - --> $DIR/union-derive-clone.rs:6:10 - | -LL | #[derive(Clone)] - | ^^^^^ the trait `Copy` is not implemented for `U1` - | -note: required by a bound in `AssertParamIsCopy` - --> $SRC_DIR/core/src/clone.rs:LL:COL - | -LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> { - | ^^^^ required by this bound in `AssertParamIsCopy` - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider annotating `U1` with `#[derive(Copy)]` - | -LL | #[derive(Copy)] - | - error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0599. diff --git a/src/test/ui/union/union-fields-1.mirunsafeck.stderr b/src/test/ui/union/union-fields-1.mirunsafeck.stderr index 5b932b9626c28..0c9981c69fcba 100644 --- a/src/test/ui/union/union-fields-1.mirunsafeck.stderr +++ b/src/test/ui/union/union-fields-1.mirunsafeck.stderr @@ -5,7 +5,7 @@ LL | union U1 { | -- field in this union ... LL | c: u8, - | ^^^^^ + | ^ | note: the lint level is defined here --> $DIR/union-fields-1.rs:4:9 @@ -19,13 +19,13 @@ error: field `a` is never read LL | union U2 { | -- field in this union LL | a: u8, - | ^^^^^ + | ^ error: field `a` is never read --> $DIR/union-fields-1.rs:16:20 | LL | union NoDropLike { a: u8 } - | ---------- ^^^^^ + | ---------- ^ | | | field in this union @@ -36,7 +36,7 @@ LL | union U { | - field in this union ... LL | c: u8, - | ^^^^^ + | ^ error: aborting due to 4 previous errors diff --git a/src/test/ui/union/union-fields-1.thirunsafeck.stderr b/src/test/ui/union/union-fields-1.thirunsafeck.stderr index 5b932b9626c28..0c9981c69fcba 100644 --- a/src/test/ui/union/union-fields-1.thirunsafeck.stderr +++ b/src/test/ui/union/union-fields-1.thirunsafeck.stderr @@ -5,7 +5,7 @@ LL | union U1 { | -- field in this union ... LL | c: u8, - | ^^^^^ + | ^ | note: the lint level is defined here --> $DIR/union-fields-1.rs:4:9 @@ -19,13 +19,13 @@ error: field `a` is never read LL | union U2 { | -- field in this union LL | a: u8, - | ^^^^^ + | ^ error: field `a` is never read --> $DIR/union-fields-1.rs:16:20 | LL | union NoDropLike { a: u8 } - | ---------- ^^^^^ + | ---------- ^ | | | field in this union @@ -36,7 +36,7 @@ LL | union U { | - field in this union ... LL | c: u8, - | ^^^^^ + | ^ error: aborting due to 4 previous errors diff --git a/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr b/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr index f6e515f840068..6e21584c37c06 100644 --- a/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr +++ b/src/test/ui/union/union-lint-dead-code.mirunsafeck.stderr @@ -5,7 +5,7 @@ LL | union Foo { | --- field in this union LL | x: usize, LL | b: bool, - | ^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/union-lint-dead-code.rs:4:9 diff --git a/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr b/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr index f6e515f840068..6e21584c37c06 100644 --- a/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr +++ b/src/test/ui/union/union-lint-dead-code.thirunsafeck.stderr @@ -5,7 +5,7 @@ LL | union Foo { | --- field in this union LL | x: usize, LL | b: bool, - | ^^^^^^^ + | ^ | note: the lint level is defined here --> $DIR/union-lint-dead-code.rs:4:9 diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr index f55fbea6336e3..53050cf539eaf 100644 --- a/src/test/ui/union/union-move.mirunsafeck.stderr +++ b/src/test/ui/union/union-move.mirunsafeck.stderr @@ -27,7 +27,7 @@ LL | move_out(x.f1_nocopy); | ^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs index 8f78c30d67a55..b8b1ac8046a03 100644 --- a/src/test/ui/union/union-move.rs +++ b/src/test/ui/union/union-move.rs @@ -3,20 +3,20 @@ //! Test the behavior of moving out of non-`Copy` union fields. //! Avoid types that `Drop`, we want to focus on moving. -#![feature(untagged_unions)] use std::cell::RefCell; +use std::mem::ManuallyDrop; fn move_out<T>(x: T) {} union U1 { - f1_nocopy: RefCell<i32>, - f2_nocopy: RefCell<i32>, + f1_nocopy: ManuallyDrop<RefCell<i32>>, + f2_nocopy: ManuallyDrop<RefCell<i32>>, f3_copy: i32, } union U2 { - f1_nocopy: RefCell<i32>, + f1_nocopy: ManuallyDrop<RefCell<i32>>, } impl Drop for U2 { fn drop(&mut self) {} diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr index f55fbea6336e3..53050cf539eaf 100644 --- a/src/test/ui/union/union-move.thirunsafeck.stderr +++ b/src/test/ui/union/union-move.thirunsafeck.stderr @@ -27,7 +27,7 @@ LL | move_out(x.f1_nocopy); | ^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-nonrepresentable.rs b/src/test/ui/union/union-nonrepresentable.rs index 4dbd97ea957ba..4bdf7c6872fa5 100644 --- a/src/test/ui/union/union-nonrepresentable.rs +++ b/src/test/ui/union/union-nonrepresentable.rs @@ -1,8 +1,6 @@ -#![feature(untagged_unions)] - union U { //~ ERROR recursive type `U` has infinite size a: u8, - b: U, + b: std::mem::ManuallyDrop<U>, } fn main() {} diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 7da7c870e704b..9804b1418b208 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -1,16 +1,16 @@ error[E0072]: recursive type `U` has infinite size - --> $DIR/union-nonrepresentable.rs:3:1 + --> $DIR/union-nonrepresentable.rs:1:1 | LL | union U { | ^^^^^^^ recursive type has infinite size LL | a: u8, -LL | b: U, - | - recursive without indirection +LL | b: std::mem::ManuallyDrop<U>, + | ------------------------- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable | -LL | b: Box<U>, - | ++++ + +LL | b: Box<std::mem::ManuallyDrop<U>>, + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr index ae84cc7811bb3..9abf440f73569 100644 --- a/src/test/ui/union/union-repr-c.stderr +++ b/src/test/ui/union/union-repr-c.stderr @@ -14,10 +14,8 @@ LL | #![deny(improper_ctypes)] note: the type is defined here --> $DIR/union-repr-c.rs:9:1 | -LL | / union W { -LL | | a: u8, -LL | | } - | |_^ +LL | union W { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index b84cb3eff56f6..cb852eff0c60a 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -1,18 +1,18 @@ -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; union Foo<T: ?Sized> { - value: T, + value: ManuallyDrop<T>, //~^ ERROR the size for values of type } struct Foo2<T: ?Sized> { - value: T, + value: ManuallyDrop<T>, //~^ ERROR the size for values of type t: u32, } enum Foo3<T: ?Sized> { - Value(T), + Value(ManuallyDrop<T>), //~^ ERROR the size for values of type } diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 3fe6e71f3b863..771e8f2619995 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -3,9 +3,10 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim | LL | union Foo<T: ?Sized> { | - this type parameter needs to be `std::marker::Sized` -LL | value: T, - | ^ doesn't have a size known at compile-time +LL | value: ManuallyDrop<T>, + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop<T>` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -15,21 +16,22 @@ LL + union Foo<T> { | help: borrowed types always have a statically known size | -LL | value: &T, +LL | value: &ManuallyDrop<T>, | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | value: Box<T>, - | ++++ + +LL | value: Box<ManuallyDrop<T>>, + | ++++ + error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:9:12 | LL | struct Foo2<T: ?Sized> { | - this type parameter needs to be `std::marker::Sized` -LL | value: T, - | ^ doesn't have a size known at compile-time +LL | value: ManuallyDrop<T>, + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop<T>` = note: only the last field of a struct may have a dynamically sized type = help: change the field's type to have a statically known size help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -39,21 +41,22 @@ LL + struct Foo2<T> { | help: borrowed types always have a statically known size | -LL | value: &T, +LL | value: &ManuallyDrop<T>, | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | value: Box<T>, - | ++++ + +LL | value: Box<ManuallyDrop<T>>, + | ++++ + error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:15:11 | LL | enum Foo3<T: ?Sized> { | - this type parameter needs to be `std::marker::Sized` -LL | Value(T), - | ^ doesn't have a size known at compile-time +LL | Value(ManuallyDrop<T>), + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop<T>` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -63,12 +66,12 @@ LL + enum Foo3<T> { | help: borrowed types always have a statically known size | -LL | Value(&T), +LL | Value(&ManuallyDrop<T>), | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | Value(Box<T>), - | ++++ + +LL | Value(Box<ManuallyDrop<T>>), + | ++++ + error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-unsafe.mir.stderr b/src/test/ui/union/union-unsafe.mir.stderr index 318b00ddea94e..544213dbc5543 100644 --- a/src/test/ui/union/union-unsafe.mir.stderr +++ b/src/test/ui/union/union-unsafe.mir.stderr @@ -1,29 +1,13 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:34:5 + --> $DIR/union-unsafe.rs:33:5 | LL | *(u.p) = 13; | ^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:39:5 - | -LL | u.a = (RefCell::new(0), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:5 - | -LL | u.a.0 = RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:47:6 + --> $DIR/union-unsafe.rs:46:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -31,7 +15,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:6 + --> $DIR/union-unsafe.rs:52:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -39,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:61:13 + --> $DIR/union-unsafe.rs:60:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -47,7 +31,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:64:14 + --> $DIR/union-unsafe.rs:63:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -55,7 +39,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:65:12 + --> $DIR/union-unsafe.rs:64:12 | LL | if let U1 { a: 12 } = u1 {} | ^^^^^^^^^^^^ access to union field @@ -63,7 +47,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:70:6 + --> $DIR/union-unsafe.rs:69:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -71,7 +55,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:74:6 + --> $DIR/union-unsafe.rs:73:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -79,13 +63,13 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:78:6 + --> $DIR/union-unsafe.rs:77:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 3cb3a18cb7544..5e1837a901d46 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,7 +1,6 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] use std::mem::ManuallyDrop; use std::cell::RefCell; @@ -26,7 +25,7 @@ union URef { } union URefCell { // field that does not drop but is not `Copy`, either - a: (RefCell<i32>, i32), + a: (ManuallyDrop<RefCell<i32>>, i32), } fn deref_union_field(mut u: URef) { @@ -36,8 +35,8 @@ fn deref_union_field(mut u: URef) { fn assign_noncopy_union_field(mut u: URefCell) { // FIXME(thir-unsafeck) - u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping - u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping + u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop) + u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop) u.a.1 = 1; // OK } diff --git a/src/test/ui/union/union-unsafe.thir.stderr b/src/test/ui/union/union-unsafe.thir.stderr index a8c3886657f43..f959fe5bdb5c5 100644 --- a/src/test/ui/union/union-unsafe.thir.stderr +++ b/src/test/ui/union/union-unsafe.thir.stderr @@ -1,29 +1,13 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:34:6 + --> $DIR/union-unsafe.rs:33:6 | LL | *(u.p) = 13; | ^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:39:5 - | -LL | u.a = (RefCell::new(0), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:5 - | -LL | u.a.0 = RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:47:6 + --> $DIR/union-unsafe.rs:46:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -31,7 +15,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:6 + --> $DIR/union-unsafe.rs:52:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -39,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:61:13 + --> $DIR/union-unsafe.rs:60:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -47,7 +31,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:64:14 + --> $DIR/union-unsafe.rs:63:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -55,7 +39,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:65:8 + --> $DIR/union-unsafe.rs:64:8 | LL | if let U1 { a: 12 } = u1 {} | ^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -63,7 +47,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:70:6 + --> $DIR/union-unsafe.rs:69:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -71,7 +55,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:74:6 + --> $DIR/union-unsafe.rs:73:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -79,13 +63,13 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:78:6 + --> $DIR/union-unsafe.rs:77:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/union/union-unsized.mirunsafeck.stderr b/src/test/ui/union/union-unsized.mirunsafeck.stderr index 36e782ac0424d..59ab835fba22d 100644 --- a/src/test/ui/union/union-unsized.mirunsafeck.stderr +++ b/src/test/ui/union/union-unsized.mirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:7:8 + --> $DIR/union-unsized.rs:5:8 | LL | a: str, | ^^^ doesn't have a size known at compile-time @@ -17,7 +17,7 @@ LL | a: Box<str>, | ++++ + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:15:8 + --> $DIR/union-unsized.rs:13:8 | LL | b: str, | ^^^ doesn't have a size known at compile-time diff --git a/src/test/ui/union/union-unsized.rs b/src/test/ui/union/union-unsized.rs index e9792f527dc71..8e897d7d3c6d6 100644 --- a/src/test/ui/union/union-unsized.rs +++ b/src/test/ui/union/union-unsized.rs @@ -1,8 +1,6 @@ // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - union U { a: str, //~^ ERROR the size for values of type diff --git a/src/test/ui/union/union-unsized.thirunsafeck.stderr b/src/test/ui/union/union-unsized.thirunsafeck.stderr index 36e782ac0424d..59ab835fba22d 100644 --- a/src/test/ui/union/union-unsized.thirunsafeck.stderr +++ b/src/test/ui/union/union-unsized.thirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:7:8 + --> $DIR/union-unsized.rs:5:8 | LL | a: str, | ^^^ doesn't have a size known at compile-time @@ -17,7 +17,7 @@ LL | a: Box<str>, | ++++ + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:15:8 + --> $DIR/union-unsized.rs:13:8 | LL | b: str, | ^^^ doesn't have a size known at compile-time diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 5c40787febfb7..98a9bd07ed21d 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -16,7 +16,7 @@ LL | / pub struct Box< LL | | T: ?Sized, LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique<T>, A); - | |________________- doesn't satisfy `Box<dyn Foo>: Clone` + | |_- doesn't satisfy `Box<dyn Foo>: Clone` | = note: the following trait bounds were not satisfied: `dyn Foo: Sized` diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index 02ce371c8d5ef..7af9c684b72e3 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -13,7 +13,7 @@ LL | / pub struct Box< LL | | T: ?Sized, LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique<T>, A); - | |________________- doesn't satisfy `Box<R>: Clone` + | |_- doesn't satisfy `Box<R>: Clone` | = note: the following trait bounds were not satisfied: `R: Clone` diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr index 14052486cbbc9..65d866c716e0e 100644 --- a/src/test/ui/unop-move-semantics.stderr +++ b/src/test/ui/unop-move-semantics.stderr @@ -46,13 +46,25 @@ error[E0507]: cannot move out of `*m` which is behind a mutable reference --> $DIR/unop-move-semantics.rs:24:6 | LL | !*m; - | ^^ move occurs because `*m` has type `T`, which does not implement the `Copy` trait + | -^^ + | || + | |move occurs because `*m` has type `T`, which does not implement the `Copy` trait + | `*m` moved due to usage in operator + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | fn not(self) -> Self::Output; + | ^^^^ error[E0507]: cannot move out of `*n` which is behind a shared reference --> $DIR/unop-move-semantics.rs:26:6 | LL | !*n; - | ^^ move occurs because `*n` has type `T`, which does not implement the `Copy` trait + | -^^ + | || + | |move occurs because `*n` has type `T`, which does not implement the `Copy` trait + | `*n` moved due to usage in operator error: aborting due to 5 previous errors diff --git a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr index cd338ac9e3a27..0ecd5203dd9d9 100644 --- a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr +++ b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:20:5 + --> $DIR/union-assignop.rs:19:5 | LL | foo.a += 5; | ^^^^^^^^^^ access to union field @@ -7,20 +7,20 @@ LL | foo.a += 5; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:21:5 + --> $DIR/union-assignop.rs:20:6 | -LL | foo.b += Dropping; - | ^^^^^ access to union field +LL | *foo.b += NonCopy; + | ^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:22:5 +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-assignop.rs:21:6 | -LL | foo.b = Dropping; - | ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping +LL | *foo.b = NonCopy; + | ^^^^^ access to union field | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-assignop.rs:23:5 @@ -46,14 +46,6 @@ LL | foo.b = foo.b; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:27:5 - | -LL | foo.b = foo.b; - | ^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/union-assignop.rs b/src/test/ui/unsafe/union-assignop.rs index c4be20aa567b7..5e667cd10d59f 100644 --- a/src/test/ui/unsafe/union-assignop.rs +++ b/src/test/ui/unsafe/union-assignop.rs @@ -1,30 +1,29 @@ // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - use std::ops::AddAssign; +use std::mem::ManuallyDrop; -struct Dropping; -impl AddAssign for Dropping { +struct NonCopy; +impl AddAssign for NonCopy { fn add_assign(&mut self, _: Self) {} } union Foo { a: u8, // non-dropping - b: Dropping, // treated as dropping + b: ManuallyDrop<NonCopy>, } fn main() { let mut foo = Foo { a: 42 }; foo.a += 5; //~ ERROR access to union field is unsafe - foo.b += Dropping; //~ ERROR access to union field is unsafe - foo.b = Dropping; //~ ERROR assignment to union field that might need dropping is unsafe + *foo.b += NonCopy; //~ ERROR access to union field is unsafe + *foo.b = NonCopy; //~ ERROR access to union field is unsafe + foo.b = ManuallyDrop::new(NonCopy); foo.a; //~ ERROR access to union field is unsafe let foo = Foo { a: 42 }; foo.b; //~ ERROR access to union field is unsafe let mut foo = Foo { a: 42 }; foo.b = foo.b; //~^ ERROR access to union field is unsafe - //~| ERROR assignment to union field that might need dropping } diff --git a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr index 71de421a2553e..24b357e762bba 100644 --- a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr +++ b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:20:5 + --> $DIR/union-assignop.rs:19:5 | LL | foo.a += 5; | ^^^^^ access to union field @@ -7,20 +7,20 @@ LL | foo.a += 5; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:21:5 + --> $DIR/union-assignop.rs:20:6 | -LL | foo.b += Dropping; - | ^^^^^ access to union field +LL | *foo.b += NonCopy; + | ^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:22:5 +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-assignop.rs:21:6 | -LL | foo.b = Dropping; - | ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping +LL | *foo.b = NonCopy; + | ^^^^^ access to union field | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-assignop.rs:23:5 @@ -38,14 +38,6 @@ LL | foo.b; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:27:5 - | -LL | foo.b = foo.b; - | ^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-assignop.rs:27:13 | @@ -54,6 +46,6 @@ LL | foo.b = foo.b; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/union-modification.rs b/src/test/ui/unsafe/union-modification.rs index 5c70b78df7c12..9a53ef9085200 100644 --- a/src/test/ui/unsafe/union-modification.rs +++ b/src/test/ui/unsafe/union-modification.rs @@ -2,8 +2,6 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - union Foo { bar: i8, _blah: isize, diff --git a/src/test/ui/unsafe/union.rs b/src/test/ui/unsafe/union.rs index 5fe09933cfc48..4338d78eabb9d 100644 --- a/src/test/ui/unsafe/union.rs +++ b/src/test/ui/unsafe/union.rs @@ -1,19 +1,19 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - union Foo { bar: i8, zst: (), pizza: Pizza, } +#[derive(Clone, Copy)] struct Pizza { topping: Option<PizzaTopping> } #[allow(dead_code)] +#[derive(Clone, Copy)] enum PizzaTopping { Cheese, Pineapple, diff --git a/src/test/ui/unsized/box-instead-of-dyn-fn.stderr b/src/test/ui/unsized/box-instead-of-dyn-fn.stderr index b9d51d21e9af2..c96c59afc5a54 100644 --- a/src/test/ui/unsized/box-instead-of-dyn-fn.stderr +++ b/src/test/ui/unsized/box-instead-of-dyn-fn.stderr @@ -14,8 +14,8 @@ LL | | LL | | } | |_____- `if` and `else` have incompatible types | - = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:32]` - found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:43]>` + = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:16]` + found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:25]>` error[E0746]: return type cannot have an unboxed trait object --> $DIR/box-instead-of-dyn-fn.rs:5:56 diff --git a/src/test/ui/unsized/issue-91801.stderr b/src/test/ui/unsized/issue-91801.stderr index e854514958629..8795aa1687f3d 100644 --- a/src/test/ui/unsized/issue-91801.stderr +++ b/src/test/ui/unsized/issue-91801.stderr @@ -5,7 +5,7 @@ LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> | ^^^^^^^^^^^^^ doesn't have a size known at compile-time | = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits> -help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 12:6]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` +help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 10:70]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` | LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/test/ui/unsized/return-unsized-from-trait-method.rs b/src/test/ui/unsized/return-unsized-from-trait-method.rs index ebe6edd101014..f053f4b0af89c 100644 --- a/src/test/ui/unsized/return-unsized-from-trait-method.rs +++ b/src/test/ui/unsized/return-unsized-from-trait-method.rs @@ -7,7 +7,7 @@ trait Foo { fn foo(f: Option<&dyn Foo>) { if let Some(f) = f { let _ = f.foo(); - //~^ ERROR cannot move a value of type [u8]: the size of [u8] cannot be statically determined + //~^ ERROR cannot move a value of type `[u8]` } } diff --git a/src/test/ui/unsized/return-unsized-from-trait-method.stderr b/src/test/ui/unsized/return-unsized-from-trait-method.stderr index 4dd7cf5e02fc2..671d409937cac 100644 --- a/src/test/ui/unsized/return-unsized-from-trait-method.stderr +++ b/src/test/ui/unsized/return-unsized-from-trait-method.stderr @@ -1,8 +1,8 @@ -error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined +error[E0161]: cannot move a value of type `[u8]` --> $DIR/return-unsized-from-trait-method.rs:9:17 | LL | let _ = f.foo(); - | ^^^^^^^ + | ^^^^^^^ the size of `[u8]` cannot be statically determined error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index 3eecca0fa09d9..0221ef16b4965 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -2,10 +2,12 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:11:11 | LL | foo11("bar", &"baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn AsRef<Path>` + = note: required for the cast from `str` to the object type `dyn AsRef<Path>` help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>` | LL | foo11(&"bar", &"baz"); @@ -15,10 +17,12 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:13:19 | LL | foo12(&"bar", "baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn AsRef<Path>` + = note: required for the cast from `str` to the object type `dyn AsRef<Path>` help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>` | LL | foo12(&"bar", &"baz"); @@ -28,10 +32,12 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:16:11 | LL | foo21("bar", &"baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn AsRef<str>` + = note: required for the cast from `str` to the object type `dyn AsRef<str>` help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>` | LL | foo21(&"bar", &"baz"); @@ -41,10 +47,12 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/unsized-fn-param.rs:18:19 | LL | foo22(&"bar", "baz"); - | ^^^^^ doesn't have a size known at compile-time + | ----- ^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn AsRef<str>` + = note: required for the cast from `str` to the object type `dyn AsRef<str>` help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>` | LL | foo22(&"bar", &"baz"); diff --git a/src/test/ui/unsized/unsized3.rs b/src/test/ui/unsized/unsized3.rs index 39b6583bc4ec4..af76aca2c2958 100644 --- a/src/test/ui/unsized/unsized3.rs +++ b/src/test/ui/unsized/unsized3.rs @@ -44,6 +44,7 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) { fn f10<X: ?Sized>(x1: Box<S<X>>) { f5(&(32, *x1)); //~^ ERROR the size for values of type + //~| ERROR the size for values of type } pub fn main() {} diff --git a/src/test/ui/unsized/unsized3.stderr b/src/test/ui/unsized/unsized3.stderr index 65bdc4c2ea352..d64091b15eb1f 100644 --- a/src/test/ui/unsized/unsized3.stderr +++ b/src/test/ui/unsized/unsized3.stderr @@ -100,6 +100,29 @@ LL - fn f9<X: ?Sized>(x1: Box<S<X>>) { LL + fn f9<X>(x1: Box<S<X>>) { | +error[E0277]: the size for values of type `X` cannot be known at compilation time + --> $DIR/unsized3.rs:45:9 + | +LL | fn f10<X: ?Sized>(x1: Box<S<X>>) { + | - this type parameter needs to be `std::marker::Sized` +LL | f5(&(32, *x1)); + | -- ^^^^^^^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | +note: required because it appears within the type `S<X>` + --> $DIR/unsized3.rs:28:8 + | +LL | struct S<X: ?Sized> { + | ^ + = note: required because it appears within the type `({integer}, S<X>)` + = note: tuples must have a statically known size to be initialized +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn f10<X: ?Sized>(x1: Box<S<X>>) { +LL + fn f10<X>(x1: Box<S<X>>) { + | + error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:45:8 | @@ -116,13 +139,21 @@ note: required because it appears within the type `S<X>` LL | struct S<X: ?Sized> { | ^ = note: required because it appears within the type `({integer}, S<X>)` - = note: tuples must have a statically known size to be initialized +note: required by a bound in `f5` + --> $DIR/unsized3.rs:24:7 + | +LL | fn f5<Y>(x: &Y) {} + | ^ required by this bound in `f5` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn f10<X: ?Sized>(x1: Box<S<X>>) { LL + fn f10<X>(x1: Box<S<X>>) { | +help: consider relaxing the implicit `Sized` restriction + | +LL | fn f5<Y: ?Sized>(x: &Y) {} + | ++++++++ -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/unspecified-self-in-trait-ref.stderr index 2ba9218715773..7869176bb3ad2 100644 --- a/src/test/ui/unspecified-self-in-trait-ref.stderr +++ b/src/test/ui/unspecified-self-in-trait-ref.stderr @@ -91,13 +91,11 @@ LL | let e = <dyn Bar::<usize>>::lol(); error[E0393]: the type parameter `A` must be explicitly specified --> $DIR/unspecified-self-in-trait-ref.rs:26:13 | -LL | / pub trait Bar<X=usize, A=Self> { -LL | | fn foo(&self); -LL | | } - | |_- type parameter `A` must be specified for this +LL | pub trait Bar<X=usize, A=Self> { + | ------------------------------ type parameter `A` must be specified for this ... -LL | let e = Bar::<usize>::lol(); - | ^^^^^^^^^^^^ missing reference to `A` +LL | let e = Bar::<usize>::lol(); + | ^^^^^^^^^^^^ missing reference to `A` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs index f02a368d4e097..ba72f74f20ce6 100644 --- a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs @@ -1,6 +1,10 @@ // Test that the "C-unwind" ABI is feature-gated, and cannot be used when the // `c_unwind` feature gate is not used. +#![allow(ffi_unwind_calls)] +//~^ WARNING unknown lint: `ffi_unwind_calls` +//~| WARNING unknown lint: `ffi_unwind_calls` + extern "C-unwind" fn f() {} //~^ ERROR C-unwind ABI is experimental and subject to change [E0658] diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr index f4c785a235f67..a67f46cd2e3b6 100644 --- a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr @@ -1,5 +1,16 @@ +warning: unknown lint: `ffi_unwind_calls` + --> $DIR/feature-gate-c-unwind.rs:4:1 + | +LL | #![allow(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_lints)]` on by default + = note: the `ffi_unwind_calls` lint is unstable + = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + error[E0658]: C-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-c-unwind.rs:4:8 + --> $DIR/feature-gate-c-unwind.rs:8:8 | LL | extern "C-unwind" fn f() {} | ^^^^^^^^^^ @@ -7,6 +18,16 @@ LL | extern "C-unwind" fn f() {} = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information = help: add `#![feature(c_unwind)]` to the crate attributes to enable -error: aborting due to previous error +warning: unknown lint: `ffi_unwind_calls` + --> $DIR/feature-gate-c-unwind.rs:4:1 + | +LL | #![allow(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `ffi_unwind_calls` lint is unstable + = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + +error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs new file mode 100644 index 0000000000000..dadf4b1218784 --- /dev/null +++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs @@ -0,0 +1,27 @@ +// build-pass +// needs-unwind +// ignore-wasm32-bare compiled with panic=abort by default + +#![feature(c_unwind)] +#![warn(ffi_unwind_calls)] + +mod foo { + #[no_mangle] + pub extern "C-unwind" fn foo() {} +} + +extern "C-unwind" { + fn foo(); +} + +fn main() { + // Call to Rust function is fine. + foo::foo(); + // Call to foreign function should warn. + unsafe { foo(); } + //~^ WARNING call to foreign function with FFI-unwind ABI + let ptr: extern "C-unwind" fn() = foo::foo; + // Call to function pointer should also warn. + ptr(); + //~^ WARNING call to function pointer with FFI-unwind ABI +} diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr new file mode 100644 index 0000000000000..ed41cb74623cb --- /dev/null +++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr @@ -0,0 +1,20 @@ +warning: call to foreign function with FFI-unwind ABI + --> $DIR/ffi-unwind-calls-lint.rs:21:14 + | +LL | unsafe { foo(); } + | ^^^^^ call to foreign function with FFI-unwind ABI + | +note: the lint level is defined here + --> $DIR/ffi-unwind-calls-lint.rs:6:9 + | +LL | #![warn(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^ + +warning: call to function pointer with FFI-unwind ABI + --> $DIR/ffi-unwind-calls-lint.rs:25:5 + | +LL | ptr(); + | ^^^^^ call to function pointer with FFI-unwind ABI + +warning: 2 warnings emitted + diff --git a/src/test/ui/use/use-from-trait-xc.stderr b/src/test/ui/use/use-from-trait-xc.stderr index 14523afbdac05..4c4c2f6225f1a 100644 --- a/src/test/ui/use/use-from-trait-xc.stderr +++ b/src/test/ui/use/use-from-trait-xc.stderr @@ -50,7 +50,7 @@ note: the struct `Foo` is defined here --> $DIR/auxiliary/use-from-trait-xc.rs:9:1 | LL | struct Foo; - | ^^^^^^^^^^^ + | ^^^^^^^^^^ error[E0603]: struct `Foo` is private --> $DIR/use-from-trait-xc.rs:17:24 @@ -62,7 +62,7 @@ note: the struct `Foo` is defined here --> $DIR/auxiliary/use-from-trait-xc.rs:9:1 | LL | struct Foo; - | ^^^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/variance/variance-associated-consts.stderr b/src/test/ui/variance/variance-associated-consts.stderr index d1bf34781dfb2..219f5bca9e301 100644 --- a/src/test/ui/variance/variance-associated-consts.stderr +++ b/src/test/ui/variance/variance-associated-consts.stderr @@ -1,10 +1,8 @@ error[E0208]: [o] --> $DIR/variance-associated-consts.rs:13:1 | -LL | / struct Foo<T: Trait> { -LL | | field: [u8; <T as Trait>::Const] -LL | | } - | |_^ +LL | struct Foo<T: Trait> { + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/variance/variance-associated-types.stderr b/src/test/ui/variance/variance-associated-types.stderr index b9aa9695f6224..94f770eda33ef 100644 --- a/src/test/ui/variance/variance-associated-types.stderr +++ b/src/test/ui/variance/variance-associated-types.stderr @@ -1,18 +1,14 @@ error[E0208]: [-, +] --> $DIR/variance-associated-types.rs:13:1 | -LL | / struct Foo<'a, T : Trait<'a>> { -LL | | field: (T, &'a ()) -LL | | } - | |_^ +LL | struct Foo<'a, T : Trait<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o, o] --> $DIR/variance-associated-types.rs:18:1 | -LL | / struct Bar<'a, T : Trait<'a>> { -LL | | field: <T as Trait<'a>>::Type -LL | | } - | |_^ +LL | struct Bar<'a, T : Trait<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-object-types.stderr b/src/test/ui/variance/variance-object-types.stderr index 2a5d8f91e1ec9..ceee53aff105d 100644 --- a/src/test/ui/variance/variance-object-types.stderr +++ b/src/test/ui/variance/variance-object-types.stderr @@ -1,10 +1,8 @@ error[E0208]: [o] --> $DIR/variance-object-types.rs:7:1 | -LL | / struct Foo<'a> { -LL | | x: Box<dyn Fn(i32) -> &'a i32 + 'static> -LL | | } - | |_^ +LL | struct Foo<'a> { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/variance/variance-regions-direct.stderr b/src/test/ui/variance/variance-regions-direct.stderr index 8c9c89955bd34..25fb22732151c 100644 --- a/src/test/ui/variance/variance-regions-direct.stderr +++ b/src/test/ui/variance/variance-regions-direct.stderr @@ -1,64 +1,44 @@ error[E0208]: [-, -, -] --> $DIR/variance-regions-direct.rs:9:1 | -LL | / struct Test2<'a, 'b, 'c> { -LL | | x: &'a isize, -LL | | y: &'b [isize], -LL | | c: &'c str -LL | | } - | |_^ +LL | struct Test2<'a, 'b, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+, +, +] --> $DIR/variance-regions-direct.rs:18:1 | -LL | / struct Test3<'a, 'b, 'c> { -LL | | x: extern "Rust" fn(&'a isize), -LL | | y: extern "Rust" fn(&'b [isize]), -LL | | c: extern "Rust" fn(&'c str), -LL | | } - | |_^ +LL | struct Test3<'a, 'b, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [-, o] --> $DIR/variance-regions-direct.rs:27:1 | -LL | / struct Test4<'a, 'b:'a> { -LL | | x: &'a mut &'b isize, -LL | | } - | |_^ +LL | struct Test4<'a, 'b:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+, o] --> $DIR/variance-regions-direct.rs:35:1 | -LL | / struct Test5<'a, 'b:'a> { -LL | | x: extern "Rust" fn(&'a mut &'b isize), -LL | | } - | |_^ +LL | struct Test5<'a, 'b:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [-, o] --> $DIR/variance-regions-direct.rs:45:1 | -LL | / struct Test6<'a, 'b:'a> { -LL | | x: &'a mut extern "Rust" fn(&'b isize), -LL | | } - | |_^ +LL | struct Test6<'a, 'b:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [*] --> $DIR/variance-regions-direct.rs:52:1 | -LL | / struct Test7<'a> { -LL | | x: isize -LL | | } - | |_^ +LL | struct Test7<'a> { + | ^^^^^^^^^^^^^^^^ error[E0208]: [+, -, o] --> $DIR/variance-regions-direct.rs:59:1 | -LL | / enum Test8<'a, 'b, 'c:'b> { -LL | | Test8A(extern "Rust" fn(&'a isize)), -LL | | Test8B(&'b [isize]), -LL | | Test8C(&'b mut &'c str), -LL | | } - | |_^ +LL | enum Test8<'a, 'b, 'c:'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/variance/variance-regions-indirect.stderr b/src/test/ui/variance/variance-regions-indirect.stderr index 17efc6231d5e7..fc52492d7efdd 100644 --- a/src/test/ui/variance/variance-regions-indirect.stderr +++ b/src/test/ui/variance/variance-regions-indirect.stderr @@ -1,44 +1,32 @@ error[E0208]: [+, -, o, *] --> $DIR/variance-regions-indirect.rs:8:1 | -LL | / enum Base<'a, 'b, 'c:'b, 'd> { -LL | | Test8A(extern "Rust" fn(&'a isize)), -LL | | Test8B(&'b [isize]), -LL | | Test8C(&'b mut &'c str), -LL | | } - | |_^ +LL | enum Base<'a, 'b, 'c:'b, 'd> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [*, o, -, +] --> $DIR/variance-regions-indirect.rs:15:1 | -LL | / struct Derived1<'w, 'x:'y, 'y, 'z> { -LL | | f: Base<'z, 'y, 'x, 'w> -LL | | } - | |_^ +LL | struct Derived1<'w, 'x:'y, 'y, 'z> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o, o, *] --> $DIR/variance-regions-indirect.rs:20:1 | -LL | / struct Derived2<'a, 'b:'a, 'c> { -LL | | f: Base<'a, 'a, 'b, 'c> -LL | | } - | |_^ +LL | struct Derived2<'a, 'b:'a, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o, -, *] --> $DIR/variance-regions-indirect.rs:25:1 | -LL | / struct Derived3<'a:'b, 'b, 'c> { -LL | | f: Base<'a, 'b, 'a, 'c> -LL | | } - | |_^ +LL | struct Derived3<'a:'b, 'b, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+, -, o] --> $DIR/variance-regions-indirect.rs:30:1 | -LL | / struct Derived4<'a, 'b, 'c:'b> { -LL | | f: Base<'a, 'b, 'c, 'a> -LL | | } - | |_^ +LL | struct Derived4<'a, 'b, 'c:'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/variance/variance-trait-bounds.stderr b/src/test/ui/variance/variance-trait-bounds.stderr index 98bc1b003c39d..e3ef339f423bc 100644 --- a/src/test/ui/variance/variance-trait-bounds.stderr +++ b/src/test/ui/variance/variance-trait-bounds.stderr @@ -1,34 +1,26 @@ error[E0208]: [+, +] --> $DIR/variance-trait-bounds.rs:16:1 | -LL | / struct TestStruct<U,T:Setter<U>> { -LL | | t: T, u: U -LL | | } - | |_^ +LL | struct TestStruct<U,T:Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [*, +] --> $DIR/variance-trait-bounds.rs:21:1 | -LL | / enum TestEnum<U,T:Setter<U>> { -LL | | Foo(T) -LL | | } - | |_^ +LL | enum TestEnum<U,T:Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [*, +] --> $DIR/variance-trait-bounds.rs:26:1 | -LL | / struct TestContraStruct<U,T:Setter<U>> { -LL | | t: T -LL | | } - | |_^ +LL | struct TestContraStruct<U,T:Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [*, +] --> $DIR/variance-trait-bounds.rs:31:1 | -LL | / struct TestBox<U,T:Getter<U>+Setter<U>> { -LL | | t: T -LL | | } - | |_^ +LL | struct TestBox<U,T:Getter<U>+Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/variance/variance-trait-object-bound.stderr b/src/test/ui/variance/variance-trait-object-bound.stderr index fb0fab1950cef..c86cf1f82b45d 100644 --- a/src/test/ui/variance/variance-trait-object-bound.stderr +++ b/src/test/ui/variance/variance-trait-object-bound.stderr @@ -1,10 +1,8 @@ error[E0208]: [-] --> $DIR/variance-trait-object-bound.rs:14:1 | -LL | / struct TOption<'a> { -LL | | v: Option<Box<dyn T + 'a>>, -LL | | } - | |_^ +LL | struct TOption<'a> { + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/variance/variance-types-bounds.stderr b/src/test/ui/variance/variance-types-bounds.stderr index 5cffdffc7f2d4..dbe8af75d5178 100644 --- a/src/test/ui/variance/variance-types-bounds.stderr +++ b/src/test/ui/variance/variance-types-bounds.stderr @@ -1,46 +1,32 @@ error[E0208]: [+, +] --> $DIR/variance-types-bounds.rs:7:1 | -LL | / struct TestImm<A, B> { -LL | | x: A, -LL | | y: B, -LL | | } - | |_^ +LL | struct TestImm<A, B> { + | ^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+, o] --> $DIR/variance-types-bounds.rs:13:1 | -LL | / struct TestMut<A, B:'static> { -LL | | x: A, -LL | | y: &'static mut B, -LL | | } - | |_^ +LL | struct TestMut<A, B:'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+, o] --> $DIR/variance-types-bounds.rs:19:1 | -LL | / struct TestIndirect<A:'static, B:'static> { -LL | | m: TestMut<A, B> -LL | | } - | |_^ +LL | struct TestIndirect<A:'static, B:'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o, o] --> $DIR/variance-types-bounds.rs:24:1 | -LL | / struct TestIndirect2<A:'static, B:'static> { -LL | | n: TestMut<A, B>, -LL | | m: TestMut<B, A> -LL | | } - | |_^ +LL | struct TestIndirect2<A:'static, B:'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o, o] --> $DIR/variance-types-bounds.rs:38:1 | -LL | / struct TestObject<A, R> { -LL | | n: Box<dyn Setter<A>+Send>, -LL | | m: Box<dyn Getter<R>+Send>, -LL | | } - | |_^ +LL | struct TestObject<A, R> { + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/variance/variance-types.stderr b/src/test/ui/variance/variance-types.stderr index 05bd4747cf168..8358b18b73ce2 100644 --- a/src/test/ui/variance/variance-types.stderr +++ b/src/test/ui/variance/variance-types.stderr @@ -1,52 +1,38 @@ error[E0208]: [-, o, o] --> $DIR/variance-types.rs:10:1 | -LL | / struct InvariantMut<'a,A:'a,B:'a> { -LL | | t: &'a mut (A,B) -LL | | } - | |_^ +LL | struct InvariantMut<'a,A:'a,B:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o] --> $DIR/variance-types.rs:15:1 | -LL | / struct InvariantCell<A> { -LL | | t: Cell<A> -LL | | } - | |_^ +LL | struct InvariantCell<A> { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [o] --> $DIR/variance-types.rs:20:1 | -LL | / struct InvariantIndirect<A> { -LL | | t: InvariantCell<A> -LL | | } - | |_^ +LL | struct InvariantIndirect<A> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+] --> $DIR/variance-types.rs:25:1 | -LL | / struct Covariant<A> { -LL | | t: A, u: fn() -> A -LL | | } - | |_^ +LL | struct Covariant<A> { + | ^^^^^^^^^^^^^^^^^^^ error[E0208]: [-] --> $DIR/variance-types.rs:30:1 | -LL | / struct Contravariant<A> { -LL | | t: fn(A) -LL | | } - | |_^ +LL | struct Contravariant<A> { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0208]: [+, -, o] --> $DIR/variance-types.rs:35:1 | -LL | / enum Enum<A,B,C> { -LL | | Foo(Covariant<A>), -LL | | Bar(Contravariant<B>), -LL | | Zed(Covariant<C>,Contravariant<C>) -LL | | } - | |_^ +LL | enum Enum<A,B,C> { + | ^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/wasm-custom-section-relocations.stderr b/src/test/ui/wasm-custom-section-relocations.stderr index eb8ab2644a330..a37edc51d1975 100644 --- a/src/test/ui/wasm-custom-section-relocations.stderr +++ b/src/test/ui/wasm-custom-section-relocations.stderr @@ -2,13 +2,13 @@ error: statics with a custom `#[link_section]` must be a simple list of bytes on --> $DIR/wasm-custom-section-relocations.rs:4:1 | LL | pub static A: &[u8] = &[1]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ error: statics with a custom `#[link_section]` must be a simple list of bytes on the wasm target with no extra levels of indirection such as references --> $DIR/wasm-custom-section-relocations.rs:13:1 | LL | pub static D: &usize = &C; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/issue-96810.rs b/src/test/ui/wf/issue-96810.rs new file mode 100644 index 0000000000000..c2948086b200b --- /dev/null +++ b/src/test/ui/wf/issue-96810.rs @@ -0,0 +1,12 @@ +struct S<T: Tr>(T::Assoc); + +trait Tr { + type Assoc; +} + +struct Hoge<K> { + s: S<K>, //~ ERROR the trait bound `K: Tr` is not satisfied + a: u32, +} + +fn main() {} diff --git a/src/test/ui/wf/issue-96810.stderr b/src/test/ui/wf/issue-96810.stderr new file mode 100644 index 0000000000000..1407e62b1e139 --- /dev/null +++ b/src/test/ui/wf/issue-96810.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `K: Tr` is not satisfied + --> $DIR/issue-96810.rs:8:8 + | +LL | s: S<K>, + | ^^^^ the trait `Tr` is not implemented for `K` + | +note: required by a bound in `S` + --> $DIR/issue-96810.rs:1:13 + | +LL | struct S<T: Tr>(T::Assoc); + | ^^ required by this bound in `S` +help: consider restricting type parameter `K` + | +LL | struct Hoge<K: Tr> { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr index 16d198725523e..94f6dc266245a 100644 --- a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr +++ b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr @@ -21,16 +21,16 @@ note: because this has an unmet lifetime requirement | LL | pub struct Wrapper<T: Trait>(T); | ^^^^^ introduces a `'static` lifetime requirement -note: the anonymous lifetime #1 defined here... - --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:5 +note: the anonymous lifetime as defined here... + --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:29 | LL | pub fn repro(_: Wrapper<Ref>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl` --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:1 | LL | impl Trait for Ref {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr index 3f297d222dce7..6d141a58ef953 100644 --- a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -31,8 +31,12 @@ LL | trait Trait: Sized {} error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-unsafe-trait-obj-match.rs:25:25 | -LL | let t: &dyn Trait = match opt() { - | ^^^^^^^^^^^ `Trait` cannot be made into an object +LL | let t: &dyn Trait = match opt() { + | _________________________^ +LL | | Some(()) => &S, +LL | | None => &R, +LL | | }; + | |_____^ `Trait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-unsafe-trait-obj-match.rs:6:14 diff --git a/src/test/ui/xcrate/xcrate-private-by-default.stderr b/src/test/ui/xcrate/xcrate-private-by-default.stderr index a97f55de5f833..0bdd4002f40ae 100644 --- a/src/test/ui/xcrate/xcrate-private-by-default.stderr +++ b/src/test/ui/xcrate/xcrate-private-by-default.stderr @@ -8,7 +8,7 @@ note: the static `j` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:47:1 | LL | static j: isize = 0; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error[E0603]: function `k` is private --> $DIR/xcrate-private-by-default.rs:25:29 @@ -32,7 +32,7 @@ note: the unit struct `l` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:49:1 | LL | struct l; - | ^^^^^^^^^ + | ^^^^^^^^ error[E0603]: enum `m` is private --> $DIR/xcrate-private-by-default.rs:29:35 @@ -56,7 +56,7 @@ note: the type alias `n` is defined here --> $DIR/auxiliary/static_priv_by_default.rs:51:1 | LL | type n = isize; - | ^^^^^^^^^^^^^^^ + | ^^^^^^ error[E0603]: module `foo` is private --> $DIR/xcrate-private-by-default.rs:35:29 diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 6338e467055cd..efe3f2b618be3 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -184,7 +184,7 @@ static PKG_INSTALLERS: &[&str] = &["x86_64-apple-darwin", "aarch64-apple-darwin" static MINGW: &[&str] = &["i686-pc-windows-gnu", "x86_64-pc-windows-gnu"]; -static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview", "rust-analyzer-preview"]; +static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview"]; macro_rules! t { ($e:expr) => { @@ -403,6 +403,7 @@ impl Builder { rename("rustfmt", "rustfmt-preview"); rename("clippy", "clippy-preview"); rename("miri", "miri-preview"); + rename("rust-analyzer", "rust-analyzer-preview"); } fn rust_package(&mut self, manifest: &Manifest) -> Package { diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index cf8840ff6ee89..352a855561417 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -10,5 +10,5 @@ anyhow = "1.0.34" curl = "0.4.38" indexmap = { version = "1.7.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } -serde_json = "1.0.59" +serde_json = { version = "1.0.59", features = ["preserve_order"] } toml = "0.5.7" diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index 1c839fdc00a08..aa346daf7e5f3 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -198,9 +198,12 @@ struct Stage0 { #[derive(Debug, serde::Serialize, serde::Deserialize)] struct Config { dist_server: String, - artifacts_server: String, - artifacts_with_llvm_assertions_server: String, - git_merge_commit_email: String, + // There are other fields in the configuration, which will be read by src/bootstrap or other + // tools consuming stage0.json. To avoid the need to update bump-stage0 every time a new field + // is added, we collect all the fields in an untyped Value and serialize them back with the + // same order and structure they were deserialized in. + #[serde(flatten)] + other: serde_json::Value, } #[derive(Debug, serde::Serialize, serde::Deserialize)] diff --git a/src/tools/cargo b/src/tools/cargo index a5e08c4703f20..8827baaa781b3 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit a5e08c4703f202e30cdaf80ca3e7c00baa59c496 +Subproject commit 8827baaa781b37872134c1ba692a6f0aeb37890e diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index ff471207b65a3..81ef072bbb07f 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v1.4.4 with: - node-version: '12.x' + node-version: '14.x' - name: Install remark run: npm install remark-cli remark-lint remark-lint-maximum-line-length remark-preset-lint-recommended remark-gfm diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 6aaf12ed9324a..9bc93c1cb42c9 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -3348,6 +3348,7 @@ Released 2018-09-13 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const +[`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access [`default_union_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_union_representation @@ -3399,6 +3400,7 @@ Released 2018-09-13 [`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call [`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used [`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy +[`explicit_auto_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_auto_deref [`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop [`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods [`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop @@ -3519,6 +3521,7 @@ Released 2018-09-13 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map +[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map @@ -3526,6 +3529,8 @@ Released 2018-09-13 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains +[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid +[`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index e4060ce29a7b5..644ca6318f625 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.63" +version = "0.1.64" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -31,6 +31,7 @@ termize = "0.1" compiletest_rs = { version = "0.8", features = ["tmp"] } tester = "0.9" regex = "1.5" +toml = "0.5" # This is used by the `collect-metadata` alias. filetime = "0.2" diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index edbc626e354b5..2c3defeaa8307 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 500 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. @@ -214,6 +214,14 @@ specifying the minimum supported Rust version (MSRV) in the clippy configuration msrv = "1.30.0" ``` +Alternatively, the [`rust-version` field](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field) +in the `Cargo.toml` can be used. + +```toml +# Cargo.toml +rust-version = "1.30" +``` + The MSRV can also be specified as an inner attribute, like below. ```rust diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md index de1f70d7e9640..6248d588a890b 100644 --- a/src/tools/clippy/book/src/README.md +++ b/src/tools/clippy/book/src/README.md @@ -1,12 +1,12 @@ # Clippy [](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto) -[](#license) +[](https://github.com/rust-lang/rust-clippy#license) A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 500 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index 3da07fcb96863..d06297f2e079a 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -13,7 +13,6 @@ because that's clearly a non-descriptive name. - [Testing](#testing) - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - - [Edition 2018 tests](#edition-2018-tests) - [Testing manually](#testing-manually) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) @@ -402,9 +401,8 @@ need to ensure that the MSRV configured for the project is >= the MSRV of the required Rust feature. If multiple features are required, just use the one with a lower MSRV. -First, add an MSRV alias for the required feature in -[`clippy_utils::msrvs`](/clippy_utils/src/msrvs.rs). This can be accessed later -as `msrvs::STR_STRIP_PREFIX`, for example. +First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`]. +This can be accessed later as `msrvs::STR_STRIP_PREFIX`, for example. ```rust msrv_aliases! { @@ -468,6 +466,8 @@ define_Conf! { } ``` +[`clippy_utils::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/msrvs/index.html + ## Author lint If you have trouble implementing your lint, there is also the internal `author` @@ -583,8 +583,7 @@ the workspace directory. Adding a configuration to a lint can be useful for thresholds or to constrain some behavior that can be seen as a false positive for some users. Adding a configuration is done in the following steps: -1. Adding a new configuration entry to - [clippy_lints::utils::conf](/clippy_lints/src/utils/conf.rs) like this: +1. Adding a new configuration entry to [`clippy_lints::utils::conf`] like this: ```rust /// Lint: LINT_NAME. @@ -635,9 +634,9 @@ for some users. Adding a configuration is done in the following steps: ``` 3. Passing the configuration value to the lint impl struct: - First find the struct construction in the [clippy_lints lib - file](/clippy_lints/src/lib.rs). The configuration value is now cloned or - copied into a local value that is then passed to the impl struct like this: + First find the struct construction in the [`clippy_lints` lib file]. The + configuration value is now cloned or copied into a local value that is then + passed to the impl struct like this: ```rust // Default generated registration: @@ -653,12 +652,16 @@ for some users. Adding a configuration is done in the following steps: 4. Adding tests: 1. The default configured value can be tested like any normal lint in - [`tests/ui`](/tests/ui). - 2. The configuration itself will be tested separately in - [`tests/ui-toml`](/tests/ui-toml). Simply add a new subfolder with a - fitting name. This folder contains a `clippy.toml` file with the - configuration value and a rust file that should be linted by Clippy. The - test can otherwise be written as usual. + [`tests/ui`]. + 2. The configuration itself will be tested separately in [`tests/ui-toml`]. + Simply add a new subfolder with a fitting name. This folder contains a + `clippy.toml` file with the configuration value and a rust file that + should be linted by Clippy. The test can otherwise be written as usual. + +[`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs +[`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs +[`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui +[`tests/ui-toml`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui-toml ## Cheat Sheet diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md index 78c429ea01322..605897ff49cdb 100644 --- a/src/tools/clippy/book/src/development/basics.md +++ b/src/tools/clippy/book/src/development/basics.md @@ -98,7 +98,7 @@ cargo dev setup intellij ``` More about intellij command usage and reasons -[here](../CONTRIBUTING.md#intellij-rust) +[here](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust) ## lintcheck diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md index e1ed89262f677..15e00c7d7ce4c 100644 --- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md +++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md @@ -276,4 +276,4 @@ functions to deal with macros: [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html [pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty -[paths]: ../clippy_utils/src/paths.rs +[paths]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/paths/index.html diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md index 337680aa3139b..5d858e0da4689 100644 --- a/src/tools/clippy/book/src/usage.md +++ b/src/tools/clippy/book/src/usage.md @@ -148,4 +148,4 @@ clippy-driver --edition 2018 -Cpanic=abort foo.rs > that are not optimized as expected, for example. [Installation]: installation.md -[CI]: continuous_integration +[CI]: continuous_integration/index.md diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index b0d470a2124d8..2ac3b4fe2ed4f 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] aho-corasick = "0.7" -clap = "3.1" +clap = "3.2" indoc = "1.0" itertools = "0.10.1" opener = "0.5" diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 81e807cf10c7c..fe69284ab10e4 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(once_cell)] #![feature(rustc_private)] diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 2c27a0bcaf95e..243a901503f16 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -5,6 +5,7 @@ use clap::{Arg, ArgAction, ArgMatches, Command, PossibleValue}; use clippy_dev::{bless, fmt, lint, new_lint, serve, setup, update_lints}; use indoc::indoc; + fn main() { let matches = get_clap_config(); @@ -85,6 +86,11 @@ fn main() { let uplift = matches.contains_id("uplift"); update_lints::rename(old_name, new_name, uplift); }, + Some(("deprecate", matches)) => { + let name = matches.get_one::<String>("name").unwrap(); + let reason = matches.get_one("reason"); + update_lints::deprecate(name, reason); + }, _ => {}, } } @@ -266,6 +272,18 @@ fn get_clap_config() -> ArgMatches { .long("uplift") .help("This lint will be uplifted into rustc"), ]), + Command::new("deprecate").about("Deprecates the given lint").args([ + Arg::new("name") + .index(1) + .required(true) + .help("The name of the lint to deprecate"), + Arg::new("reason") + .long("reason") + .short('r') + .required(false) + .takes_value(true) + .help("The reason for deprecation"), + ]), ]) .get_matches() } diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 748d73c080126..7d7e760ef446c 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -138,7 +138,7 @@ fn to_camel_case(name: &str) -> String { .collect() } -fn get_stabilization_version() -> String { +pub(crate) fn get_stabilization_version() -> String { fn parse_manifest(contents: &str) -> Option<String> { let version = contents .lines() diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 1bbd9a45b619e..2e0659f42d7b6 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -1,16 +1,17 @@ +use crate::clippy_project_root; use aho_corasick::AhoCorasickBuilder; -use core::fmt::Write as _; +use indoc::writedoc; use itertools::Itertools; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; -use std::fs; -use std::io::{self, Read as _, Seek as _, Write as _}; +use std::fmt::Write; +use std::fs::{self, OpenOptions}; +use std::io::{self, Read, Seek, SeekFrom, Write as _}; +use std::ops::Range; use std::path::{Path, PathBuf}; use walkdir::{DirEntry, WalkDir}; -use crate::clippy_project_root; - const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ // Use that command to update this file and do not edit by hand.\n\ // Manual edits will be overwritten.\n\n"; @@ -326,6 +327,200 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) { println!("note: `cargo uitest` still needs to be run to update the test results"); } +const DEFAULT_DEPRECATION_REASON: &str = "default deprecation note"; +/// Runs the `deprecate` command +/// +/// This does the following: +/// * Adds an entry to `deprecated_lints.rs`. +/// * Removes the lint declaration (and the entire file if applicable) +/// +/// # Panics +/// +/// If a file path could not read from or written to +pub fn deprecate(name: &str, reason: Option<&String>) { + fn finish( + (lints, mut deprecated_lints, renamed_lints): (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>), + name: &str, + reason: &str, + ) { + deprecated_lints.push(DeprecatedLint { + name: name.to_string(), + reason: reason.to_string(), + declaration_range: Range::default(), + }); + + generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + println!("info: `{}` has successfully been deprecated", name); + + if reason == DEFAULT_DEPRECATION_REASON { + println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`"); + } + println!("note: you must run `cargo uitest` to update the test results"); + } + + let reason = reason.map_or(DEFAULT_DEPRECATION_REASON, String::as_str); + let name_lower = name.to_lowercase(); + let name_upper = name.to_uppercase(); + + let (mut lints, deprecated_lints, renamed_lints) = gather_all(); + let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{}`", name); return; }; + + let mod_path = { + let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module)); + if mod_path.is_dir() { + mod_path = mod_path.join("mod"); + } + + mod_path.set_extension("rs"); + mod_path + }; + + let deprecated_lints_path = &*clippy_project_root().join("clippy_lints/src/deprecated_lints.rs"); + + if remove_lint_declaration(&name_lower, &mod_path, &mut lints).unwrap_or(false) { + declare_deprecated(&name_upper, deprecated_lints_path, reason).unwrap(); + finish((lints, deprecated_lints, renamed_lints), name, reason); + return; + } + + eprintln!("error: lint not found"); +} + +fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io::Result<bool> { + fn remove_lint(name: &str, lints: &mut Vec<Lint>) { + lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos)); + } + + fn remove_test_assets(name: &str) { + let test_file_stem = format!("tests/ui/{}", name); + let path = Path::new(&test_file_stem); + + // Some lints have their own directories, delete them + if path.is_dir() { + fs::remove_dir_all(path).ok(); + return; + } + + // Remove all related test files + fs::remove_file(path.with_extension("rs")).ok(); + fs::remove_file(path.with_extension("stderr")).ok(); + fs::remove_file(path.with_extension("fixed")).ok(); + } + + fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) { + let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| { + content + .find("declare_lint_pass!") + .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`")) + }); + let mut impl_lint_pass_end = content[impl_lint_pass_start..] + .find(']') + .expect("failed to find `impl_lint_pass` terminator"); + + impl_lint_pass_end += impl_lint_pass_start; + if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(&lint_name_upper) { + let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); + for c in content[lint_name_end..impl_lint_pass_end].chars() { + // Remove trailing whitespace + if c == ',' || c.is_whitespace() { + lint_name_end += 1; + } else { + break; + } + } + + content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, ""); + } + } + + if path.exists() { + if let Some(lint) = lints.iter().find(|l| l.name == name) { + if lint.module == name { + // The lint name is the same as the file, we can just delete the entire file + fs::remove_file(path)?; + } else { + // We can't delete the entire file, just remove the declaration + + if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) { + // Remove clippy_lints/src/some_mod/some_lint.rs + let mut lint_mod_path = path.to_path_buf(); + lint_mod_path.set_file_name(name); + lint_mod_path.set_extension("rs"); + + fs::remove_file(lint_mod_path).ok(); + } + + let mut content = + fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + + eprintln!( + "warn: you will have to manually remove any code related to `{}` from `{}`", + name, + path.display() + ); + + assert!( + content[lint.declaration_range.clone()].contains(&name.to_uppercase()), + "error: `{}` does not contain lint `{}`'s declaration", + path.display(), + lint.name + ); + + // Remove lint declaration (declare_clippy_lint!) + content.replace_range(lint.declaration_range.clone(), ""); + + // Remove the module declaration (mod xyz;) + let mod_decl = format!("\nmod {};", name); + content = content.replacen(&mod_decl, "", 1); + + remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content); + fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy())); + } + + remove_test_assets(name); + remove_lint(name, lints); + return Ok(true); + } + } + + Ok(false) +} + +fn declare_deprecated(name: &str, path: &Path, reason: &str) -> io::Result<()> { + let mut file = OpenOptions::new().write(true).open(path)?; + + file.seek(SeekFrom::End(0))?; + + let version = crate::new_lint::get_stabilization_version(); + let deprecation_reason = if reason == DEFAULT_DEPRECATION_REASON { + "TODO" + } else { + reason + }; + + writedoc!( + file, + " + + declare_deprecated_lint! {{ + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// {} + #[clippy::version = \"{}\"] + pub {}, + \"{}\" + }} + + ", + deprecation_reason, + version, + name, + reason, + ) +} + /// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there /// were no replacements. fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option<String> { @@ -393,16 +588,18 @@ struct Lint { group: String, desc: String, module: String, + declaration_range: Range<usize>, } impl Lint { #[must_use] - fn new(name: &str, group: &str, desc: &str, module: &str) -> Self { + fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self { Self { name: name.to_lowercase(), group: group.into(), desc: remove_line_splices(desc), module: module.into(), + declaration_range, } } @@ -433,12 +630,14 @@ impl Lint { struct DeprecatedLint { name: String, reason: String, + declaration_range: Range<usize>, } impl DeprecatedLint { - fn new(name: &str, reason: &str) -> Self { + fn new(name: &str, reason: &str, declaration_range: Range<usize>) -> Self { Self { name: name.to_lowercase(), reason: remove_line_splices(reason), + declaration_range, } } } @@ -610,7 +809,11 @@ fn clippy_lints_src_files() -> impl Iterator<Item = (PathBuf, DirEntry)> { macro_rules! match_tokens { ($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => { { - $($(let $capture =)? if let Some((TokenKind::$token $({$($fields)*})?, _x)) = $iter.next() { + $($(let $capture =)? if let Some(LintDeclSearchResult { + token_kind: TokenKind::$token $({$($fields)*})?, + content: _x, + .. + }) = $iter.next() { _x } else { continue; @@ -621,40 +824,72 @@ macro_rules! match_tokens { } } +struct LintDeclSearchResult<'a> { + token_kind: TokenKind, + content: &'a str, + range: Range<usize>, +} + /// Parse a source file looking for `declare_clippy_lint` macro invocations. fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) { let mut offset = 0usize; let mut iter = tokenize(contents).map(|t| { let range = offset..offset + t.len; offset = range.end; - (t.kind, &contents[range]) + + LintDeclSearchResult { + token_kind: t.kind, + content: &contents[range.clone()], + range, + } }); - while iter.any(|(kind, s)| kind == TokenKind::Ident && s == "declare_clippy_lint") { + while let Some(LintDeclSearchResult { range, .. }) = iter.find( + |LintDeclSearchResult { + token_kind, content, .. + }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint", + ) { + let start = range.start; + let mut iter = iter .by_ref() - .filter(|&(kind, _)| !matches!(kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); + .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); // matches `!{` match_tokens!(iter, Bang OpenBrace); match iter.next() { // #[clippy::version = "version"] pub - Some((TokenKind::Pound, _)) => { + Some(LintDeclSearchResult { + token_kind: TokenKind::Pound, + .. + }) => { match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); }, // pub - Some((TokenKind::Ident, _)) => (), + Some(LintDeclSearchResult { + token_kind: TokenKind::Ident, + .. + }) => (), _ => continue, } + let (name, group, desc) = match_tokens!( iter, // LINT_NAME Ident(name) Comma // group, Ident(group) Comma - // "description" } - Literal{..}(desc) CloseBrace + // "description" + Literal{..}(desc) ); - lints.push(Lint::new(name, group, desc, module)); + + if let Some(LintDeclSearchResult { + token_kind: TokenKind::CloseBrace, + range, + .. + }) = iter.next() + { + lints.push(Lint::new(name, group, desc, module, start..range.end)); + } } } @@ -664,12 +899,24 @@ fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) { let mut iter = tokenize(contents).map(|t| { let range = offset..offset + t.len; offset = range.end; - (t.kind, &contents[range]) + + LintDeclSearchResult { + token_kind: t.kind, + content: &contents[range.clone()], + range, + } }); - while iter.any(|(kind, s)| kind == TokenKind::Ident && s == "declare_deprecated_lint") { - let mut iter = iter - .by_ref() - .filter(|&(kind, _)| !matches!(kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); + + while let Some(LintDeclSearchResult { range, .. }) = iter.find( + |LintDeclSearchResult { + token_kind, content, .. + }| token_kind == &TokenKind::Ident && *content == "declare_deprecated_lint", + ) { + let start = range.start; + + let mut iter = iter.by_ref().filter(|LintDeclSearchResult { ref token_kind, .. }| { + !matches!(token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }) + }); let (name, reason) = match_tokens!( iter, // !{ @@ -680,10 +927,16 @@ fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) { Ident Ident(name) Comma // "description" Literal{kind: LiteralKind::Str{..},..}(reason) - // } - CloseBrace ); - lints.push(DeprecatedLint::new(name, reason)); + + if let Some(LintDeclSearchResult { + token_kind: TokenKind::CloseBrace, + range, + .. + }) = iter.next() + { + lints.push(DeprecatedLint::new(name, reason, start..range.end)); + } } } @@ -693,8 +946,14 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) { let mut iter = tokenize(line).map(|t| { let range = offset..offset + t.len; offset = range.end; - (t.kind, &line[range]) + + LintDeclSearchResult { + token_kind: t.kind, + content: &line[range.clone()], + range, + } }); + let (old_name, new_name) = match_tokens!( iter, // ("old_name", @@ -844,10 +1103,25 @@ mod tests { "#; let mut result = Vec::new(); parse_contents(CONTENTS, "module_name", &mut result); + for r in &mut result { + r.declaration_range = Range::default(); + } let expected = vec![ - Lint::new("ptr_arg", "style", "\"really long text\"", "module_name"), - Lint::new("doc_markdown", "pedantic", "\"single line\"", "module_name"), + Lint::new( + "ptr_arg", + "style", + "\"really long text\"", + "module_name", + Range::default(), + ), + Lint::new( + "doc_markdown", + "pedantic", + "\"single line\"", + "module_name", + Range::default(), + ), ]; assert_eq!(expected, result); } @@ -865,10 +1139,14 @@ mod tests { let mut result = Vec::new(); parse_deprecated_contents(DEPRECATED_CONTENTS, &mut result); + for r in &mut result { + r.declaration_range = Range::default(); + } let expected = vec![DeprecatedLint::new( "should_assert_eq", "\"`assert!()` will be more flexible with RFC 2011\"", + Range::default(), )]; assert_eq!(expected, result); } @@ -876,15 +1154,34 @@ mod tests { #[test] fn test_usable_lints() { let lints = vec![ - Lint::new("should_assert_eq2", "Not Deprecated", "\"abc\"", "module_name"), - Lint::new("should_assert_eq2", "internal", "\"abc\"", "module_name"), - Lint::new("should_assert_eq2", "internal_style", "\"abc\"", "module_name"), + Lint::new( + "should_assert_eq2", + "Not Deprecated", + "\"abc\"", + "module_name", + Range::default(), + ), + Lint::new( + "should_assert_eq2", + "internal", + "\"abc\"", + "module_name", + Range::default(), + ), + Lint::new( + "should_assert_eq2", + "internal_style", + "\"abc\"", + "module_name", + Range::default(), + ), ]; let expected = vec![Lint::new( "should_assert_eq2", "Not Deprecated", "\"abc\"", "module_name", + Range::default(), )]; assert_eq!(expected, Lint::usable_lints(&lints)); } @@ -892,21 +1189,33 @@ mod tests { #[test] fn test_by_lint_group() { let lints = vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name"), - Lint::new("should_assert_eq2", "group2", "\"abc\"", "module_name"), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name"), + Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq2", + "group2", + "\"abc\"", + "module_name", + Range::default(), + ), + Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap<String, Vec<Lint>> = HashMap::new(); expected.insert( "group1".to_string(), vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name"), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name"), + Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ], ); expected.insert( "group2".to_string(), - vec![Lint::new("should_assert_eq2", "group2", "\"abc\"", "module_name")], + vec![Lint::new( + "should_assert_eq2", + "group2", + "\"abc\"", + "module_name", + Range::default(), + )], ); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); } @@ -914,8 +1223,12 @@ mod tests { #[test] fn test_gen_deprecated() { let lints = vec![ - DeprecatedLint::new("should_assert_eq", "\"has been superseded by should_assert_eq2\""), - DeprecatedLint::new("another_deprecated", "\"will be removed\""), + DeprecatedLint::new( + "should_assert_eq", + "\"has been superseded by should_assert_eq2\"", + Range::default(), + ), + DeprecatedLint::new("another_deprecated", "\"will be removed\"", Range::default()), ]; let expected = GENERATED_FILE_COMMENT.to_string() @@ -940,9 +1253,9 @@ mod tests { #[test] fn test_gen_lint_group_list() { let lints = vec![ - Lint::new("abc", "group1", "\"abc\"", "module_name"), - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name"), - Lint::new("internal", "internal_style", "\"abc\"", "module_name"), + Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()), ]; let expected = GENERATED_FILE_COMMENT.to_string() + &[ diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 4d5bf47833fb8..79a56dc405d17 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.63" +version = "0.1.64" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -10,7 +10,6 @@ edition = "2021" [dependencies] cargo_metadata = "0.14" -clippy_dev = { path = "../clippy_dev", optional = true } clippy_utils = { path = "../clippy_utils" } if_chain = "1.0" itertools = "0.10.1" @@ -32,7 +31,7 @@ url = { version = "2.2", features = ["serde"] } [features] deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default -internal = ["clippy_utils/internal", "serde_json", "tempfile", "clippy_dev"] +internal = ["clippy_utils/internal", "serde_json", "tempfile"] [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/src/tools/clippy/clippy_lints/src/assign_ops.rs b/src/tools/clippy/clippy_lints/src/assign_ops.rs deleted file mode 100644 index f81da2d422333..0000000000000 --- a/src/tools/clippy/clippy_lints/src/assign_ops.rs +++ /dev/null @@ -1,235 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; -use clippy_utils::ty::implements_trait; -use clippy_utils::{binop_traits, sugg}; -use clippy_utils::{eq_expr_value, trait_ref_of_method}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `a = a op b` or `a = b commutative_op a` - /// patterns. - /// - /// ### Why is this bad? - /// These can be written as the shorter `a op= b`. - /// - /// ### Known problems - /// While forbidden by the spec, `OpAssign` traits may have - /// implementations that differ from the regular `Op` impl. - /// - /// ### Example - /// ```rust - /// let mut a = 5; - /// let b = 0; - /// // ... - /// - /// a = a + b; - /// ``` - /// - /// Use instead: - /// ```rust - /// let mut a = 5; - /// let b = 0; - /// // ... - /// - /// a += b; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub ASSIGN_OP_PATTERN, - style, - "assigning the result of an operation on a variable to that same variable" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `a op= a op b` or `a op= b op a` patterns. - /// - /// ### Why is this bad? - /// Most likely these are bugs where one meant to write `a - /// op= b`. - /// - /// ### Known problems - /// Clippy cannot know for sure if `a op= a op b` should have - /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. - /// If `a op= a op b` is really the correct behavior it should be - /// written as `a = a op a op b` as it's less confusing. - /// - /// ### Example - /// ```rust - /// let mut a = 5; - /// let b = 2; - /// // ... - /// a += a + b; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MISREFACTORED_ASSIGN_OP, - suspicious, - "having a variable on both sides of an assign op" -} - -declare_lint_pass!(AssignOps => [ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP]); - -impl<'tcx> LateLintPass<'tcx> for AssignOps { - #[allow(clippy::too_many_lines)] - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - match &expr.kind { - hir::ExprKind::AssignOp(op, lhs, rhs) => { - if let hir::ExprKind::Binary(binop, l, r) = &rhs.kind { - if op.node != binop.node { - return; - } - // lhs op= l op r - if eq_expr_value(cx, lhs, l) { - lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r); - } - // lhs op= l commutative_op r - if is_commutative(op.node) && eq_expr_value(cx, lhs, r) { - lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l); - } - } - }, - hir::ExprKind::Assign(assignee, e, _) => { - if let hir::ExprKind::Binary(op, l, r) = &e.kind { - let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { - let ty = cx.typeck_results().expr_ty(assignee); - let rty = cx.typeck_results().expr_ty(rhs); - if_chain! { - if let Some((_, lang_item)) = binop_traits(op.node); - if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item); - let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id); - if trait_ref_of_method(cx, parent_fn) - .map_or(true, |t| t.path.res.def_id() != trait_id); - if implements_trait(cx, ty, trait_id, &[rty.into()]); - then { - span_lint_and_then( - cx, - ASSIGN_OP_PATTERN, - expr.span, - "manual implementation of an assign operation", - |diag| { - if let (Some(snip_a), Some(snip_r)) = - (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) - { - diag.span_suggestion( - expr.span, - "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r), - Applicability::MachineApplicable, - ); - } - }, - ); - } - } - }; - - let mut visitor = ExprVisitor { - assignee, - counter: 0, - cx, - }; - - walk_expr(&mut visitor, e); - - if visitor.counter == 1 { - // a = a op b - if eq_expr_value(cx, assignee, l) { - lint(assignee, r); - } - // a = b commutative_op a - // Limited to primitive type as these ops are know to be commutative - if eq_expr_value(cx, assignee, r) && cx.typeck_results().expr_ty(assignee).is_primitive_ty() { - match op.node { - hir::BinOpKind::Add - | hir::BinOpKind::Mul - | hir::BinOpKind::And - | hir::BinOpKind::Or - | hir::BinOpKind::BitXor - | hir::BinOpKind::BitAnd - | hir::BinOpKind::BitOr => { - lint(assignee, l); - }, - _ => {}, - } - } - } - } - }, - _ => {}, - } - } -} - -fn lint_misrefactored_assign_op( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - op: hir::BinOp, - rhs: &hir::Expr<'_>, - assignee: &hir::Expr<'_>, - rhs_other: &hir::Expr<'_>, -) { - span_lint_and_then( - cx, - MISREFACTORED_ASSIGN_OP, - expr.span, - "variable appears on both sides of an assignment operation", - |diag| { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { - let a = &sugg::Sugg::hir(cx, assignee, ".."); - let r = &sugg::Sugg::hir(cx, rhs, ".."); - let long = format!("{} = {}", snip_a, sugg::make_binop(op.node.into(), a, r)); - diag.span_suggestion( - expr.span, - &format!( - "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with", - snip_a, - snip_a, - op.node.as_str(), - snip_r, - long - ), - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r), - Applicability::MaybeIncorrect, - ); - diag.span_suggestion( - expr.span, - "or", - long, - Applicability::MaybeIncorrect, // snippet - ); - } - }, - ); -} - -#[must_use] -fn is_commutative(op: hir::BinOpKind) -> bool { - use rustc_hir::BinOpKind::{ - Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub, - }; - match op { - Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true, - Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false, - } -} - -struct ExprVisitor<'a, 'tcx> { - assignee: &'a hir::Expr<'a>, - counter: u8, - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if eq_expr_value(self.cx, self.assignee, expr) { - self.counter += 1; - } - - walk_expr(self, expr); - } -} diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index ed12ad9c36790..4bcbeacf9feb5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -78,10 +78,17 @@ declare_clippy_lint! { /// Checks for `extern crate` and `use` items annotated with /// lint attributes. /// - /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, - /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and - /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on - /// `extern crate` items with a `#[macro_use]` attribute. + /// This lint permits lint attributes for lints emitted on the items themself. + /// For `use` items these lints are: + /// * deprecated + /// * unreachable_pub + /// * unused_imports + /// * clippy::enum_glob_use + /// * clippy::macro_use_imports + /// * clippy::wildcard_imports + /// + /// For `extern crate` items these lints are: + /// * `unused_imports` on items with `#[macro_use]` /// /// ### Why is this bad? /// Lint attributes have no effect on crate imports. Most @@ -347,7 +354,10 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { || extract_clippy_lint(lint).map_or(false, |s| { matches!( s.as_str(), - "wildcard_imports" | "enum_glob_use" | "redundant_pub_crate", + "wildcard_imports" + | "enum_glob_use" + | "redundant_pub_crate" + | "macro_use_imports", ) }) { diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs index 4b3a04f1255b9..ad206b5fb304f 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BlockCheckMode, Expr, ExprKind}; +use rustc_hir::{BlockCheckMode, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -51,7 +51,7 @@ struct ExVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let ExprKind::Closure { body, .. } = expr.kind { + if let ExprKind::Closure(&Closure { body, .. }) = expr.kind { // do not lint if the closure is called using an iterator (see #1141) if_chain! { if let Some(parent) = get_parent_expr(self.cx, expr); diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index e4e122ba6eb59..526ee2f891a16 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{eq_expr_value, get_trait_def_id, paths}; @@ -394,9 +394,10 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { continue 'simplified; } if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { - span_lint_and_then( + span_lint_hir_and_then( self.cx, LOGIC_BUG, + e.hir_id, e.span, "this boolean expression contains a logic bug", |diag| { @@ -429,9 +430,10 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } let nonminimal_bool_lint = |suggestions: Vec<_>| { - span_lint_and_then( + span_lint_hir_and_then( self.cx, NONMINIMAL_BOOL, + e.hir_id, e.span, "this boolean expression can be simplified", |diag| { diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs index 4e530256321cc..326ce34082af7 100644 --- a/src/tools/clippy/clippy_lints/src/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/bytecount.rs @@ -5,7 +5,7 @@ use clippy_utils::visitors::is_local_used; use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; +use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, UintTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { if count.ident.name == sym::count; if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind; if filter.ident.name == sym!(filter); - if let ExprKind::Closure { body, .. } = filter_arg.kind; + if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; let body = cx.tcx.hir().body(body); if let [param] = body.params; if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs new file mode 100644 index 0000000000000..3c996d3d2aeee --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -0,0 +1,68 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::last_path_segment; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, paths}; +use rustc_errors::Applicability; +use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// It checks for `std::iter::Empty::default()` and suggests replacing it with + /// `std::iter::empty()`. + /// ### Why is this bad? + /// `std::iter::empty()` is the more idiomatic way. + /// ### Example + /// ```rust + /// let _ = std::iter::Empty::<usize>::default(); + /// let iter: std::iter::Empty<usize> = std::iter::Empty::default(); + /// ``` + /// Use instead: + /// ```rust + /// let _ = std::iter::empty::<usize>(); + /// let iter: std::iter::Empty<usize> = std::iter::empty(); + /// ``` + #[clippy::version = "1.63.0"] + pub DEFAULT_INSTEAD_OF_ITER_EMPTY, + style, + "check `std::iter::Empty::default()` and replace with `std::iter::empty()`" +} +declare_lint_pass!(DefaultIterEmpty => [DEFAULT_INSTEAD_OF_ITER_EMPTY]); + +impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Call(iter_expr, []) = &expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, _)) = &iter_expr.kind + && let TyKind::Path(ty_path) = &ty.kind + && let QPath::Resolved(None, path) = ty_path + && let def::Res::Def(_, def_id) = &path.res + && match_def_path(cx, *def_id, &paths::ITER_EMPTY) + { + let mut applicability = Applicability::MachineApplicable; + let sugg = make_sugg(cx, ty_path, &mut applicability); + span_lint_and_sugg( + cx, + DEFAULT_INSTEAD_OF_ITER_EMPTY, + expr.span, + "`std::iter::empty()` is the more idiomatic way", + "try", + sugg, + applicability, + ); + } + } +} + +fn make_sugg(cx: &LateContext<'_>, ty_path: &rustc_hir::QPath<'_>, applicability: &mut Applicability) -> String { + if let Some(last) = last_path_segment(ty_path).args + && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }) + { + format!("std::iter::empty::<{}>()", snippet_with_applicability(cx, iter_ty.span, "..", applicability)) + } else { + "std::iter::empty()".to_owned() + } +} diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 5d5ea0f49c8c8..9aa5af3190fb2 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -1,16 +1,21 @@ -// NOTE: if you add a deprecated lint in this file, please add a corresponding test in -// tests/ui/deprecated.rs +// NOTE: Entries should be created with `cargo dev deprecate` /// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This /// enables the simple extraction of the metadata without changing the current deprecation /// declaration. -pub struct ClippyDeprecatedLint; +pub struct ClippyDeprecatedLint { + #[allow(dead_code)] + pub desc: &'static str, +} +#[macro_export] macro_rules! declare_deprecated_lint { - { $(#[$attr:meta])* pub $name: ident, $_reason: expr} => { + { $(#[$attr:meta])* pub $name: ident, $reason: literal} => { $(#[$attr])* #[allow(dead_code)] - pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {}; + pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint { + desc: $reason + }; } } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index b47441eff3748..0f4a2f79ac5d7 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1,20 +1,24 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::peel_mid_ty_refs; -use clippy_utils::{get_parent_expr, get_parent_node, is_lint_allowed, path_to_local}; +use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res}; +use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; +use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - BindingAnnotation, Body, BodyId, BorrowKind, Destination, Expr, ExprKind, HirId, MatchSource, Mutability, Node, - Pat, PatKind, UnOp, + self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, GenericArg, HirId, ImplItem, + ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem, + TraitItemKind, TyKind, UnOp, }; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span}; +use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_trait_selection::infer::InferCtxtExt; declare_clippy_lint! { /// ### What it does @@ -104,10 +108,34 @@ declare_clippy_lint! { "`ref` binding to a reference" } +declare_clippy_lint! { + /// ### What it does + /// Checks for dereferencing expressions which would be covered by auto-deref. + /// + /// ### Why is this bad? + /// This unnecessarily complicates the code. + /// + /// ### Example + /// ```rust + /// let x = String::new(); + /// let y: &str = &*x; + /// ``` + /// Use instead: + /// ```rust + /// let x = String::new(); + /// let y: &str = &x; + /// ``` + #[clippy::version = "1.60.0"] + pub EXPLICIT_AUTO_DEREF, + complexity, + "dereferencing when the compiler would automatically dereference" +} + impl_lint_pass!(Dereferencing => [ EXPLICIT_DEREF_METHODS, NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE, + EXPLICIT_AUTO_DEREF, ]); #[derive(Default)] @@ -136,6 +164,12 @@ struct StateData { /// Span of the top level expression span: Span, hir_id: HirId, + position: Position, +} + +struct DerefedBorrow { + count: usize, + msg: &'static str, } enum State { @@ -147,11 +181,19 @@ enum State { /// The required mutability target_mut: Mutability, }, - DerefedBorrow { - count: usize, - required_precedence: i8, - msg: &'static str, + DerefedBorrow(DerefedBorrow), + ExplicitDeref { + // Span and id of the top-level deref expression if the parent expression is a borrow. + deref_span_id: Option<(Span, HirId)>, + }, + ExplicitDerefField { + name: Symbol, }, + Reborrow { + deref_span: Span, + deref_hir_id: HirId, + }, + Borrow, } // A reference operation considered by this lint pass @@ -207,13 +249,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { match (self.state.take(), kind) { (None, kind) => { - let parent = get_parent_node(cx.tcx, expr.hir_id); let expr_ty = typeck.expr_ty(expr); + let (position, adjustments) = walk_parents(cx, expr); match kind { + RefOp::Deref => { + if let Position::FieldAccess(name) = position + && !ty_contains_field(typeck.expr_ty(sub_expr), name) + { + self.state = Some(( + State::ExplicitDerefField { name }, + StateData { span: expr.span, hir_id: expr.hir_id, position }, + )); + } else if position.is_deref_stable() { + self.state = Some(( + State::ExplicitDeref { deref_span_id: None }, + StateData { span: expr.span, hir_id: expr.hir_id, position }, + )); + } + } RefOp::Method(target_mut) if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id) - && is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) => + && position.lint_explicit_deref() => { self.state = Some(( State::DerefMethod { @@ -228,12 +285,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { StateData { span: expr.span, hir_id: expr.hir_id, + position }, )); }, RefOp::AddrOf => { // Find the number of times the borrow is auto-derefed. - let mut iter = find_adjustments(cx.tcx, typeck, expr).iter(); + let mut iter = adjustments.iter(); let mut deref_count = 0usize; let next_adjust = loop { match iter.next() { @@ -274,40 +332,43 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { "this expression creates a reference which is immediately dereferenced by the compiler"; let borrow_msg = "this expression borrows a value the compiler would automatically borrow"; - let (required_refs, required_precedence, msg) = if is_auto_borrow_position(parent, expr.hir_id) - { - (1, PREC_POSTFIX, if deref_count == 1 { borrow_msg } else { deref_msg }) + let (required_refs, msg) = if position.can_auto_borrow() { + (1, if deref_count == 1 { borrow_msg } else { deref_msg }) } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) = next_adjust.map(|a| &a.kind) { - if matches!(mutability, AutoBorrowMutability::Mut { .. }) - && !is_auto_reborrow_position(parent) + if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable() { - (3, 0, deref_msg) + (3, deref_msg) } else { - (2, 0, deref_msg) + (2, deref_msg) } } else { - (2, 0, deref_msg) + (2, deref_msg) }; if deref_count >= required_refs { self.state = Some(( - State::DerefedBorrow { + State::DerefedBorrow(DerefedBorrow { // One of the required refs is for the current borrow expression, the remaining ones // can't be removed without breaking the code. See earlier comment. count: deref_count - required_refs, - required_precedence, msg, - }, + }), + StateData { span: expr.span, hir_id: expr.hir_id, position }, + )); + } else if position.is_deref_stable() { + self.state = Some(( + State::Borrow, StateData { span: expr.span, hir_id: expr.hir_id, + position }, )); } }, - _ => (), + RefOp::Method(..) => (), } }, ( @@ -334,26 +395,90 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => { + self.state = Some(( + State::DerefedBorrow(DerefedBorrow { + count: state.count - 1, + ..state + }), + data, + )); + }, + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => { + let position = data.position; + report(cx, expr, State::DerefedBorrow(state), data); + if position.is_deref_stable() { + self.state = Some(( + State::Borrow, + StateData { + span: expr.span, + hir_id: expr.hir_id, + position, + }, + )); + } + }, + (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => { + let position = data.position; + report(cx, expr, State::DerefedBorrow(state), data); + if let Position::FieldAccess(name) = position + && !ty_contains_field(typeck.expr_ty(sub_expr), name) + { + self.state = Some(( + State::ExplicitDerefField { name }, + StateData { span: expr.span, hir_id: expr.hir_id, position }, + )); + } else if position.is_deref_stable() { + self.state = Some(( + State::ExplicitDeref { deref_span_id: None }, + StateData { span: expr.span, hir_id: expr.hir_id, position }, + )); + } + }, + + (Some((State::Borrow, data)), RefOp::Deref) => { + if typeck.expr_ty(sub_expr).is_ref() { + self.state = Some(( + State::Reborrow { + deref_span: expr.span, + deref_hir_id: expr.hir_id, + }, + data, + )); + } else { + self.state = Some(( + State::ExplicitDeref { + deref_span_id: Some((expr.span, expr.hir_id)), + }, + data, + )); + } + }, ( Some(( - State::DerefedBorrow { - count, - required_precedence, - msg, + State::Reborrow { + deref_span, + deref_hir_id, }, data, )), - RefOp::AddrOf, - ) if count != 0 => { + RefOp::Deref, + ) => { self.state = Some(( - State::DerefedBorrow { - count: count - 1, - required_precedence, - msg, + State::ExplicitDeref { + deref_span_id: Some((deref_span, deref_hir_id)), }, data, )); }, + (state @ Some((State::ExplicitDeref { .. }, _)), RefOp::Deref) => { + self.state = state; + }, + (Some((State::ExplicitDerefField { name }, data)), RefOp::Deref) + if !ty_contains_field(typeck.expr_ty(sub_expr), name) => + { + self.state = Some((State::ExplicitDerefField { name }, data)); + }, (Some((state, data)), _) => report(cx, expr, state, data), } @@ -473,131 +598,362 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { } } -// Checks whether the parent node is a suitable context for switching from a deref method to the -// deref operator. -fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId, child_span: Span) -> bool { - let parent = match parent { - Some(Node::Expr(e)) if e.span.ctxt() == child_span.ctxt() => e, - _ => return true, - }; - match parent.kind { - // Leave deref calls in the middle of a method chain. - // e.g. x.deref().foo() - ExprKind::MethodCall(_, [self_arg, ..], _) if self_arg.hir_id == child_id => false, - - // Leave deref calls resulting in a called function - // e.g. (x.deref())() - ExprKind::Call(func_expr, _) if func_expr.hir_id == child_id => false, - - // Makes an ugly suggestion - // e.g. *x.deref() => *&*x - ExprKind::Unary(UnOp::Deref, _) - // Postfix expressions would require parens - | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) - | ExprKind::Field(..) - | ExprKind::Index(..) - | ExprKind::Err => false, - - ExprKind::Box(..) - | ExprKind::ConstBlock(..) - | ExprKind::Array(_) - | ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Tup(..) - | ExprKind::Binary(..) - | ExprKind::Unary(..) - | ExprKind::Lit(..) - | ExprKind::Cast(..) - | ExprKind::Type(..) - | ExprKind::DropTemps(..) - | ExprKind::If(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - | ExprKind::Let(..) - | ExprKind::Closure{..} - | ExprKind::Block(..) - | ExprKind::Assign(..) - | ExprKind::AssignOp(..) - | ExprKind::Path(..) - | ExprKind::AddrOf(..) - | ExprKind::Break(..) - | ExprKind::Continue(..) - | ExprKind::Ret(..) - | ExprKind::InlineAsm(..) - | ExprKind::Struct(..) - | ExprKind::Repeat(..) - | ExprKind::Yield(..) => true, - } +/// The position of an expression relative to it's parent. +#[derive(Clone, Copy)] +enum Position { + MethodReceiver, + /// The method is defined on a reference type. e.g. `impl Foo for &T` + MethodReceiverRefImpl, + Callee, + FieldAccess(Symbol), + Postfix, + Deref, + /// Any other location which will trigger auto-deref to a specific time. + DerefStable(i8), + /// Any other location which will trigger auto-reborrowing. + ReborrowStable(i8), + Other(i8), } +impl Position { + fn is_deref_stable(self) -> bool { + matches!(self, Self::DerefStable(_)) + } -/// Checks if the given expression is in a position which can be auto-reborrowed. -/// Note: This is only correct assuming auto-deref is already occurring. -fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool { - match parent { - Some(Node::Expr(parent)) => matches!(parent.kind, ExprKind::MethodCall(..) | ExprKind::Call(..)), - Some(Node::Local(_)) => true, - _ => false, + fn is_reborrow_stable(self) -> bool { + matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_)) } -} -/// Checks if the given expression is a position which can auto-borrow. -fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool { - if let Some(Node::Expr(parent)) = parent { - match parent.kind { - // ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id, - ExprKind::Field(..) => true, - ExprKind::Call(f, _) => f.hir_id == child_id, - _ => false, - } - } else { - false + fn can_auto_borrow(self) -> bool { + matches!(self, Self::MethodReceiver | Self::FieldAccess(_) | Self::Callee) } -} -/// Adjustments are sometimes made in the parent block rather than the expression itself. -fn find_adjustments<'tcx>( - tcx: TyCtxt<'tcx>, - typeck: &'tcx TypeckResults<'tcx>, - expr: &'tcx Expr<'tcx>, -) -> &'tcx [Adjustment<'tcx>] { - let map = tcx.hir(); - let mut iter = map.parent_iter(expr.hir_id); - let mut prev = expr; + fn lint_explicit_deref(self) -> bool { + matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_)) + } - loop { - match typeck.expr_adjustments(prev) { - [] => (), - a => break a, - }; + fn precedence(self) -> i8 { + match self { + Self::MethodReceiver + | Self::MethodReceiverRefImpl + | Self::Callee + | Self::FieldAccess(_) + | Self::Postfix => PREC_POSTFIX, + Self::Deref => PREC_PREFIX, + Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p, + } + } +} - match iter.next().map(|(_, x)| x) { - Some(Node::Block(_)) => { - if let Some((_, Node::Expr(e))) = iter.next() { - prev = e; +/// Walks up the parent expressions attempting to determine both how stable the auto-deref result +/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow +/// locations as those follow different rules. +#[allow(clippy::too_many_lines)] +fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) { + let mut adjustments = [].as_slice(); + let mut precedence = 0i8; + let ctxt = e.span.ctxt(); + let position = walk_to_expr_usage(cx, e, &mut |parent, child_id| { + // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead. + if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) { + adjustments = cx.typeck_results().expr_adjustments(e); + } + match parent { + Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => { + Some(binding_ty_auto_deref_stability(ty, precedence)) + }, + Node::Item(&Item { + kind: ItemKind::Static(..) | ItemKind::Const(..), + def_id, + span, + .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Const(..), + def_id, + span, + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Const(..), + def_id, + span, + .. + }) if span.ctxt() == ctxt => { + let ty = cx.tcx.type_of(def_id); + Some(if ty.is_ref() { + Position::DerefStable(precedence) } else { - // This shouldn't happen. Blocks are always contained in an expression. - break &[]; - } + Position::Other(precedence) + }) }, - Some(Node::Expr(&Expr { - kind: ExprKind::Break(Destination { target_id: Ok(id), .. }, _), + + Node::Item(&Item { + kind: ItemKind::Fn(..), + def_id, + span, + .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(..), + def_id, + span, + .. + }) + | Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(..), + def_id, + span, .. - })) => { - if let Some(Node::Expr(e)) = map.find(id) { - prev = e; - iter = map.parent_iter(id); + }) if span.ctxt() == ctxt => { + let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output(); + Some(if !output.is_ref() { + Position::Other(precedence) + } else if output.has_placeholders() || output.has_opaque_types() { + Position::ReborrowStable(precedence) + } else { + Position::DerefStable(precedence) + }) + }, + + Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { + ExprKind::Ret(_) => { + let output = cx + .tcx + .fn_sig(cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap())) + .skip_binder() + .output(); + Some(if !output.is_ref() { + Position::Other(precedence) + } else if output.has_placeholders() || output.has_opaque_types() { + Position::ReborrowStable(precedence) + } else { + Position::DerefStable(precedence) + }) + }, + ExprKind::Call(func, _) if func.hir_id == child_id => (child_id == e.hir_id).then(|| Position::Callee), + ExprKind::Call(func, args) => args + .iter() + .position(|arg| arg.hir_id == child_id) + .zip(expr_sig(cx, func)) + .and_then(|(i, sig)| sig.input_with_hir(i)) + .map(|(hir_ty, ty)| match hir_ty { + // Type inference for closures can depend on how they're called. Only go by the explicit + // types here. + Some(ty) => binding_ty_auto_deref_stability(ty, precedence), + None => param_auto_deref_stability(ty.skip_binder(), precedence), + }), + ExprKind::MethodCall(_, args, _) => { + let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); + args.iter().position(|arg| arg.hir_id == child_id).map(|i| { + if i == 0 { + // Check for calls to trait methods where the trait is implemented on a reference. + // Two cases need to be handled: + // * `self` methods on `&T` will never have auto-borrow + // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take + // priority. + if e.hir_id != child_id { + Position::ReborrowStable(precedence) + } else if let Some(trait_id) = cx.tcx.trait_of_item(id) + && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) + && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() + && let subs = cx.typeck_results().node_substs_opt(child_id).unwrap_or_else( + || cx.tcx.mk_substs([].iter()) + ) && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } && impl_ty.is_ref() + && cx.tcx.infer_ctxt().enter(|infcx| + infcx + .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) + .must_apply_modulo_regions() + ) + { + Position::MethodReceiverRefImpl + } else { + Position::MethodReceiver + } + } else { + param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence) + } + }) + }, + ExprKind::Struct(path, fields, _) => { + let variant = variant_of_res(cx, cx.qpath_res(path, parent.hir_id)); + fields + .iter() + .find(|f| f.expr.hir_id == child_id) + .zip(variant) + .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) + .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence)) + }, + ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), + ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), + ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) + | ExprKind::Index(child, _) + if child.hir_id == e.hir_id => + { + Some(Position::Postfix) + }, + _ if child_id == e.hir_id => { + precedence = parent.precedence().order(); + None + }, + _ => None, + }, + _ => None, + } + }) + .unwrap_or(Position::Other(precedence)); + (position, adjustments) +} + +// Checks the stability of auto-deref when assigned to a binding with the given explicit type. +// +// e.g. +// let x = Box::new(Box::new(0u32)); +// let y1: &Box<_> = x.deref(); +// let y2: &Box<_> = &x; +// +// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when +// switching to auto-dereferencing. +fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { + let TyKind::Rptr(_, ty) = &ty.kind else { + return Position::Other(precedence); + }; + let mut ty = ty; + + loop { + break match ty.ty.kind { + TyKind::Rptr(_, ref ref_ty) => { + ty = ref_ty; + continue; + }, + TyKind::Path( + QPath::TypeRelative(_, path) + | QPath::Resolved( + _, + Path { + segments: [.., path], .. + }, + ), + ) => { + if let Some(args) = path.args + && args.args.iter().any(|arg| match arg { + GenericArg::Infer(_) => true, + GenericArg::Type(ty) => ty_contains_infer(ty), + _ => false, + }) + { + Position::ReborrowStable(precedence) } else { - // This shouldn't happen. The destination should exist. - break &[]; + Position::DerefStable(precedence) } }, - _ => break &[], + TyKind::Slice(_) + | TyKind::Array(..) + | TyKind::BareFn(_) + | TyKind::Never + | TyKind::Tup(_) + | TyKind::Ptr(_) + | TyKind::TraitObject(..) + | TyKind::Path(_) => Position::DerefStable(precedence), + TyKind::OpaqueDef(..) + | TyKind::Infer + | TyKind::Typeof(..) + | TyKind::Err => Position::ReborrowStable(precedence), + }; + } +} + +// Checks whether a type is inferred at some point. +// e.g. `_`, `Box<_>`, `[_]` +fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { + struct V(bool); + impl Visitor<'_> for V { + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + if self.0 + || matches!( + ty.kind, + TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err + ) + { + self.0 = true; + } else { + walk_ty(self, ty); + } } + + fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) { + if self.0 || matches!(arg, GenericArg::Infer(_)) { + self.0 = true; + } else if let GenericArg::Type(ty) = arg { + self.visit_ty(ty); + } + } + } + let mut v = V(false); + v.visit_ty(ty); + v.0 +} + +// Checks whether a type is stable when switching to auto dereferencing, +fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { + let ty::Ref(_, mut ty, _) = *ty.kind() else { + return Position::Other(precedence); + }; + + loop { + break match *ty.kind() { + ty::Ref(_, ref_ty, _) => { + ty = ref_ty; + continue; + }, + ty::Infer(_) + | ty::Error(_) + | ty::Param(_) + | ty::Bound(..) + | ty::Opaque(..) + | ty::Placeholder(_) + | ty::Dynamic(..) => Position::ReborrowStable(precedence), + ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => { + Position::ReborrowStable(precedence) + }, + ty::Adt(..) + | ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Projection(_) => Position::DerefStable(precedence), + }; + } +} + +fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool { + if let ty::Adt(adt, _) = *ty.kind() { + adt.is_struct() && adt.all_fields().any(|f| f.name == name) + } else { + false } } -#[expect(clippy::needless_pass_by_value)] -fn report<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, state: State, data: StateData) { +#[expect(clippy::needless_pass_by_value, clippy::too_many_lines)] +fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) { match state { State::DerefMethod { ty_changed_count, @@ -647,15 +1003,14 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, state: State, data: S app, ); }, - State::DerefedBorrow { - required_precedence, - msg, - .. - } => { + State::DerefedBorrow(state) => { let mut app = Applicability::MachineApplicable; - let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0; - span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, msg, |diag| { - let sugg = if required_precedence > expr.precedence().order() && !has_enclosing_paren(&snip) { + let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); + span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| { + let sugg = if !snip_is_macro + && expr.precedence().order() < data.position.precedence() + && !has_enclosing_paren(&snip) + { format!("({})", snip) } else { snip.into() @@ -663,6 +1018,48 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, state: State, data: S diag.span_suggestion(data.span, "change this to", sugg, app); }); }, + State::ExplicitDeref { deref_span_id } => { + let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id + && !cx.typeck_results().expr_ty(expr).is_ref() + { + (span, hir_id, PREC_PREFIX) + } else { + (data.span, data.hir_id, data.position.precedence()) + }; + span_lint_hir_and_then( + cx, + EXPLICIT_AUTO_DEREF, + hir_id, + span, + "deref which would be done by auto-deref", + |diag| { + let mut app = Applicability::MachineApplicable; + let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app); + let sugg = + if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { + format!("({})", snip) + } else { + snip.into() + }; + diag.span_suggestion(span, "try this", sugg, app); + }, + ); + }, + State::ExplicitDerefField { .. } => { + span_lint_hir_and_then( + cx, + EXPLICIT_AUTO_DEREF, + data.hir_id, + data.span, + "deref which would be done by auto-deref", + |diag| { + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0; + diag.span_suggestion(data.span, "try this", snip.into_owned(), app); + }, + ); + }, + State::Borrow | State::Reborrow { .. } => (), } } diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs deleted file mode 100644 index ee0440e52ff85..0000000000000 --- a/src/tools/clippy/clippy_lints/src/double_comparison.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Lint on unnecessary double comparisons. Some examples: - -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::eq_expr_value; -use clippy_utils::source::snippet_with_applicability; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; - -declare_clippy_lint! { - /// ### What it does - /// Checks for double comparisons that could be simplified to a single expression. - /// - /// - /// ### Why is this bad? - /// Readability. - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// # let y = 2; - /// if x == y || x < y {} - /// ``` - /// - /// Use instead: - /// - /// ```rust - /// # let x = 1; - /// # let y = 2; - /// if x <= y {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DOUBLE_COMPARISONS, - complexity, - "unnecessary double comparisons that can be simplified" -} - -declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]); - -impl<'tcx> DoubleComparisons { - #[expect(clippy::similar_names)] - fn check_binop(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, span: Span) { - let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) { - (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => { - (lb.node, llhs, lrhs, rb.node, rlhs, rrhs) - }, - _ => return, - }; - if !(eq_expr_value(cx, llhs, rlhs) && eq_expr_value(cx, lrhs, rrhs)) { - return; - } - macro_rules! lint_double_comparison { - ($op:tt) => {{ - let mut applicability = Applicability::MachineApplicable; - let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability); - let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability); - let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str); - span_lint_and_sugg( - cx, - DOUBLE_COMPARISONS, - span, - "this binary expression can be simplified", - "try", - sugg, - applicability, - ); - }}; - } - #[rustfmt::skip] - match (op, lkind, rkind) { - (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => { - lint_double_comparison!(<=); - }, - (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => { - lint_double_comparison!(>=); - }, - (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => { - lint_double_comparison!(!=); - }, - (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => { - lint_double_comparison!(==); - }, - _ => (), - }; - } -} - -impl<'tcx> LateLintPass<'tcx> for DoubleComparisons { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref kind, lhs, rhs) = expr.kind { - Self::check_binop(cx, kind.node, lhs, rhs, expr.span); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index c6c7b959d4f49..4f49bb879f503 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind}; use rustc_errors::MultiSpan; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext, Level}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{FileName, Span}; use std::collections::BTreeMap; @@ -49,6 +49,7 @@ declare_clippy_lint! { struct Modules { local_path: PathBuf, spans: Vec<Span>, + lint_levels: Vec<Level>, } #[derive(Default)] @@ -70,13 +71,30 @@ impl EarlyLintPass for DuplicateMod { let modules = self.modules.entry(absolute_path).or_insert(Modules { local_path, spans: Vec::new(), + lint_levels: Vec::new(), }); modules.spans.push(item.span_with_attributes()); + modules.lint_levels.push(cx.get_lint_level(DUPLICATE_MOD)); } } fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) { - for Modules { local_path, spans } in self.modules.values() { + for Modules { local_path, spans, lint_levels } in self.modules.values() { + if spans.len() < 2 { + continue; + } + + // At this point the lint would be emitted + assert_eq!(spans.len(), lint_levels.len()); + let spans: Vec<_> = spans.into_iter().zip(lint_levels).filter_map(|(span, lvl)|{ + if let Some(id) = lvl.get_expectation_id() { + cx.fulfill_expectation(id); + } + + (!matches!(lvl, Level::Allow | Level::Expect(_))).then_some(*span) + }) + .collect(); + if spans.len() < 2 { continue; } diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs deleted file mode 100644 index d85ace3a279b3..0000000000000 --- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs +++ /dev/null @@ -1,75 +0,0 @@ -use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calculation of subsecond microseconds or milliseconds - /// from other `Duration` methods. - /// - /// ### Why is this bad? - /// It's more concise to call `Duration::subsec_micros()` or - /// `Duration::subsec_millis()` than to calculate them. - /// - /// ### Example - /// ```rust - /// # use std::time::Duration; - /// # let duration = Duration::new(5, 0); - /// let micros = duration.subsec_nanos() / 1_000; - /// let millis = duration.subsec_nanos() / 1_000_000; - /// ``` - /// - /// Use instead: - /// ```rust - /// # use std::time::Duration; - /// # let duration = Duration::new(5, 0); - /// let micros = duration.subsec_micros(); - /// let millis = duration.subsec_millis(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DURATION_SUBSEC, - complexity, - "checks for calculation of subsecond microseconds or milliseconds" -} - -declare_lint_pass!(DurationSubsec => [DURATION_SUBSEC]); - -impl<'tcx> LateLintPass<'tcx> for DurationSubsec { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, left, right) = expr.kind; - if let ExprKind::MethodCall(method_path, args, _) = left.kind; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::Duration); - if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right); - then { - let suggested_fn = match (method_path.ident.as_str(), divisor) { - ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", - ("subsec_nanos", 1_000) => "subsec_micros", - _ => return, - }; - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - DURATION_SUBSEC, - expr.span, - &format!("calling `{}()` is more concise than this calculation", suggested_fn), - "try", - format!( - "{}.{}()", - snippet_with_applicability(cx, args[0].span, "_", &mut applicability), - suggested_fn - ), - applicability, - ); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 23b7510457091..cd36f9fcd729e 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -190,7 +190,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n .map(|e| *e.0) .collect(); } - let (what, value) = match (pre.is_empty(), post.is_empty()) { + let (what, value) = match (have_no_extra_prefix(&pre), post.is_empty()) { (true, true) => return, (false, _) => ("pre", pre.join("")), (true, false) => { @@ -212,6 +212,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n ); } +#[must_use] +fn have_no_extra_prefix(prefixes: &[&str]) -> bool { + prefixes.iter().all(|p| p == &"" || p == &"_") +} + #[must_use] fn to_camel_case(item_name: &str) -> String { let mut s = String::new(); diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs deleted file mode 100644 index 2f4c90d07cf66..0000000000000 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ /dev/null @@ -1,319 +0,0 @@ -use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; -use clippy_utils::get_enclosing_block; -use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; -use clippy_utils::source::snippet; -use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for equal operands to comparison, logical and - /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, - /// `||`, `&`, `|`, `^`, `-` and `/`). - /// - /// ### Why is this bad? - /// This is usually just a typo or a copy and paste error. - /// - /// ### Known problems - /// False negatives: We had some false positives regarding - /// calls (notably [racer](https://github.com/phildawes/racer) had one instance - /// of `x.pop() && x.pop()`), so we removed matching any function or method - /// calls. We may introduce a list of known pure functions in the future. - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// if x + 1 == x + 1 {} - /// - /// // or - /// - /// # let a = 3; - /// # let b = 4; - /// assert_eq!(a, a); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub EQ_OP, - correctness, - "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for arguments to `==` which have their address - /// taken to satisfy a bound - /// and suggests to dereference the other argument instead - /// - /// ### Why is this bad? - /// It is more idiomatic to dereference the other argument. - /// - /// ### Example - /// ```rust,ignore - /// &x == y - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// x == *y - /// ``` - #[clippy::version = "pre 1.29.0"] - pub OP_REF, - style, - "taking a reference to satisfy the type constraints on `==`" -} - -declare_lint_pass!(EqOp => [EQ_OP, OP_REF]); - -impl<'tcx> LateLintPass<'tcx> for EqOp { - #[expect(clippy::similar_names, clippy::too_many_lines)] - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if_chain! { - if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { - let name = cx.tcx.item_name(macro_call.def_id); - matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne") - .then(|| (macro_call, name)) - }); - if let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn); - if eq_expr_value(cx, lhs, rhs); - if macro_call.is_local(); - if !is_in_test_function(cx.tcx, e.hir_id); - then { - span_lint( - cx, - EQ_OP, - lhs.span.to(rhs.span), - &format!("identical args used in this `{}!` macro call", macro_name), - ); - } - } - if let ExprKind::Binary(op, left, right) = e.kind { - if e.span.from_expansion() { - return; - } - let macro_with_not_op = |expr_kind: &ExprKind<'_>| { - if let ExprKind::Unary(_, expr) = *expr_kind { - expr.span.from_expansion() - } else { - false - } - }; - if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) { - return; - } - if is_useless_with_eq_exprs(op.node.into()) - && eq_expr_value(cx, left, right) - && !is_in_test_function(cx.tcx, e.hir_id) - { - span_lint( - cx, - EQ_OP, - e.span, - &format!("equal expressions as operands to `{}`", op.node.as_str()), - ); - return; - } - let (trait_id, requires_ref) = match op.node { - BinOpKind::Add => (cx.tcx.lang_items().add_trait(), false), - BinOpKind::Sub => (cx.tcx.lang_items().sub_trait(), false), - BinOpKind::Mul => (cx.tcx.lang_items().mul_trait(), false), - BinOpKind::Div => (cx.tcx.lang_items().div_trait(), false), - BinOpKind::Rem => (cx.tcx.lang_items().rem_trait(), false), - // don't lint short circuiting ops - BinOpKind::And | BinOpKind::Or => return, - BinOpKind::BitXor => (cx.tcx.lang_items().bitxor_trait(), false), - BinOpKind::BitAnd => (cx.tcx.lang_items().bitand_trait(), false), - BinOpKind::BitOr => (cx.tcx.lang_items().bitor_trait(), false), - BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false), - BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false), - BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true), - BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => { - (cx.tcx.lang_items().partial_ord_trait(), true) - }, - }; - if let Some(trait_id) = trait_id { - match (&left.kind, &right.kind) { - // do not suggest to dereference literals - (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {}, - // &foo == &bar - (&ExprKind::AddrOf(BorrowKind::Ref, _, l), &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { - let lty = cx.typeck_results().expr_ty(l); - let rty = cx.typeck_results().expr_ty(r); - let lcpy = is_copy(cx, lty); - let rcpy = is_copy(cx, rty); - if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { - if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) - || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) - { - return; // Don't lint - } - } - // either operator autorefs or both args are copyable - if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) { - span_lint_and_then( - cx, - OP_REF, - e.span, - "needlessly taken reference of both operands", - |diag| { - let lsnip = snippet(cx, l.span, "...").to_string(); - let rsnip = snippet(cx, r.span, "...").to_string(); - multispan_sugg( - diag, - "use the values directly", - vec![(left.span, lsnip), (right.span, rsnip)], - ); - }, - ); - } else if lcpy - && !rcpy - && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) - { - span_lint_and_then( - cx, - OP_REF, - e.span, - "needlessly taken reference of left operand", - |diag| { - let lsnip = snippet(cx, l.span, "...").to_string(); - diag.span_suggestion( - left.span, - "use the left value directly", - lsnip, - Applicability::MaybeIncorrect, // FIXME #2597 - ); - }, - ); - } else if !lcpy - && rcpy - && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) - { - span_lint_and_then( - cx, - OP_REF, - e.span, - "needlessly taken reference of right operand", - |diag| { - let rsnip = snippet(cx, r.span, "...").to_string(); - diag.span_suggestion( - right.span, - "use the right value directly", - rsnip, - Applicability::MaybeIncorrect, // FIXME #2597 - ); - }, - ); - } - }, - // &foo == bar - (&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => { - let lty = cx.typeck_results().expr_ty(l); - if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { - let rty = cx.typeck_results().expr_ty(right); - if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) - || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) - { - return; // Don't lint - } - } - let lcpy = is_copy(cx, lty); - if (requires_ref || lcpy) - && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) - { - span_lint_and_then( - cx, - OP_REF, - e.span, - "needlessly taken reference of left operand", - |diag| { - let lsnip = snippet(cx, l.span, "...").to_string(); - diag.span_suggestion( - left.span, - "use the left value directly", - lsnip, - Applicability::MaybeIncorrect, // FIXME #2597 - ); - }, - ); - } - }, - // foo == &bar - (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { - let rty = cx.typeck_results().expr_ty(r); - if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { - let lty = cx.typeck_results().expr_ty(left); - if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) - || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) - { - return; // Don't lint - } - } - let rcpy = is_copy(cx, rty); - if (requires_ref || rcpy) - && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) - { - span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| { - let rsnip = snippet(cx, r.span, "...").to_string(); - diag.span_suggestion( - right.span, - "use the right value directly", - rsnip, - Applicability::MaybeIncorrect, // FIXME #2597 - ); - }); - } - }, - _ => {}, - } - } - } - } -} - -fn in_impl<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - bin_op: DefId, -) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { - if_chain! { - if let Some(block) = get_enclosing_block(cx, e.hir_id); - if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()); - let item = cx.tcx.hir().expect_item(impl_def_id.expect_local()); - if let ItemKind::Impl(item) = &item.kind; - if let Some(of_trait) = &item.of_trait; - if let Some(seg) = of_trait.path.segments.last(); - if let Some(Res::Def(_, trait_id)) = seg.res; - if trait_id == bin_op; - if let Some(generic_args) = seg.args; - if let Some(GenericArg::Type(other_ty)) = generic_args.args.last(); - - then { - Some((item.self_ty, other_ty)) - } - else { - None - } - } -} - -fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { - if_chain! { - if let ty::Adt(adt_def, _) = middle_ty.kind(); - if let Some(local_did) = adt_def.did().as_local(); - let item = cx.tcx.hir().expect_item(local_did); - let middle_ty_id = item.def_id.to_def_id(); - if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; - if let Res::Def(_, hir_ty_id) = path.res; - - then { - hir_ty_id == middle_ty_id - } - else { - false - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs deleted file mode 100644 index c1a84973c4211..0000000000000 --- a/src/tools/clippy/clippy_lints/src/erasing_op.rs +++ /dev/null @@ -1,77 +0,0 @@ -use clippy_utils::consts::{constant_simple, Constant}; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::same_type_and_consts; - -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeckResults; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for erasing operations, e.g., `x * 0`. - /// - /// ### Why is this bad? - /// The whole expression can be replaced by zero. - /// This is most likely not the intended outcome and should probably be - /// corrected - /// - /// ### Example - /// ```rust - /// let x = 1; - /// 0 / x; - /// 0 * x; - /// x & 0; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub ERASING_OP, - correctness, - "using erasing operations, e.g., `x * 0` or `y & 0`" -} - -declare_lint_pass!(ErasingOp => [ERASING_OP]); - -impl<'tcx> LateLintPass<'tcx> for ErasingOp { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if e.span.from_expansion() { - return; - } - if let ExprKind::Binary(ref cmp, left, right) = e.kind { - let tck = cx.typeck_results(); - match cmp.node { - BinOpKind::Mul | BinOpKind::BitAnd => { - check(cx, tck, left, right, e); - check(cx, tck, right, left, e); - }, - BinOpKind::Div => check(cx, tck, left, right, e), - _ => (), - } - } - } -} - -fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool { - let input_ty = tck.expr_ty(input).peel_refs(); - let output_ty = tck.expr_ty(output).peel_refs(); - !same_type_and_consts(input_ty, output_ty) -} - -fn check<'tcx>( - cx: &LateContext<'tcx>, - tck: &TypeckResults<'tcx>, - op: &Expr<'tcx>, - other: &Expr<'tcx>, - parent: &Expr<'tcx>, -) { - if constant_simple(cx, tck, op) == Some(Constant::Int(0)) { - if different_types(tck, other, parent) { - return; - } - span_lint( - cx, - ERASING_OP, - parent.span, - "this operation will always return zero. This is likely not the intended outcome", - ); - } -} diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 9d21dd71e0e8d..1ac7bfba06ba2 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -1,7 +1,7 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_hir; use clippy_utils::ty::contains_ty; use rustc_hir::intravisit; -use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node}; +use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; @@ -118,9 +118,10 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { }); for node in v.set { - span_lint( + span_lint_hir( cx, BOXED_LOCAL, + node, cx.tcx.hir().span(node), "local variable doesn't need to be boxed here", ); @@ -131,7 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { // TODO: Replace with Map::is_argument(..) when it's fixed fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { match map.find(id) { - Some(Node::Binding(_)) => (), + Some(Node::Pat(Pat { + kind: PatKind::Binding(..), + .. + })) => (), _ => return false, } @@ -143,15 +147,6 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { self.set.remove(&lid); - let map = &self.cx.tcx.hir(); - if let Some(Node::Binding(_)) = map.find(cmt.hir_id) { - if self.set.contains(&lid) { - // let y = x where x is known - // remove x, insert y - self.set.insert(cmt.hir_id); - self.set.remove(&lid); - } - } } } } diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index a5a763c37d1be..80c84014bfdeb 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -7,12 +7,12 @@ use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety}; +use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable}; +use rustc_middle::ty::{self, ClosureKind, Ty, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { return; } let body = match expr.kind { - ExprKind::Closure { body, .. } => cx.tcx.hir().body(body), + ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body), _ => return, }; if body.value.span.from_expansion() { diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index f7a92bc079567..453471c8cdda6 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -94,7 +94,7 @@ impl ExcessiveBools { fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) { match fn_sig.header.ext { - Extern::Implicit | Extern::Explicit(_) => return, + Extern::Implicit(_) | Extern::Explicit(_, _) => return, Extern::None => (), } diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 12d636cf41014..5bf4313b41a49 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -125,7 +125,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) // Find id of the local that expr_end_of_block resolves to if let ExprKind::Path(QPath::Resolved(None, expr_path)) = expr_end_of_block.kind; if let Res::Local(expr_res) = expr_path.res; - if let Some(Node::Binding(res_pat)) = cx.tcx.hir().find(expr_res); + if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res); // Find id of the local we found in the block if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs deleted file mode 100644 index 98aee7592ae80..0000000000000 --- a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs +++ /dev/null @@ -1,116 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths, sugg}; -use if_chain::if_chain; -use rustc_ast::util::parser::AssocOp; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Checks for statements of the form `(a - b) < f32::EPSILON` or - /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`. - /// - /// ### Why is this bad? - /// The code without `.abs()` is more likely to have a bug. - /// - /// ### Known problems - /// If the user can ensure that b is larger than a, the `.abs()` is - /// technically unnecessary. However, it will make the code more robust and doesn't have any - /// large performance implications. If the abs call was deliberately left out for performance - /// reasons, it is probably better to state this explicitly in the code, which then can be done - /// with an allow. - /// - /// ### Example - /// ```rust - /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { - /// (a - b) < f32::EPSILON - /// } - /// ``` - /// Use instead: - /// ```rust - /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { - /// (a - b).abs() < f32::EPSILON - /// } - /// ``` - #[clippy::version = "1.48.0"] - pub FLOAT_EQUALITY_WITHOUT_ABS, - suspicious, - "float equality check without `.abs()`" -} - -declare_lint_pass!(FloatEqualityWithoutAbs => [FLOAT_EQUALITY_WITHOUT_ABS]); - -impl<'tcx> LateLintPass<'tcx> for FloatEqualityWithoutAbs { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let lhs; - let rhs; - - // check if expr is a binary expression with a lt or gt operator - if let ExprKind::Binary(op, left, right) = expr.kind { - match op.node { - BinOpKind::Lt => { - lhs = left; - rhs = right; - }, - BinOpKind::Gt => { - lhs = right; - rhs = left; - }, - _ => return, - }; - } else { - return; - } - - if_chain! { - - // left hand side is a subtraction - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Sub, - .. - }, - val_l, - val_r, - ) = lhs.kind; - - // right hand side matches either f32::EPSILON or f64::EPSILON - if let ExprKind::Path(ref epsilon_path) = rhs.kind; - if let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id); - if match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON); - - // values of the subtractions on the left hand side are of the type float - let t_val_l = cx.typeck_results().expr_ty(val_l); - let t_val_r = cx.typeck_results().expr_ty(val_r); - if let ty::Float(_) = t_val_l.kind(); - if let ty::Float(_) = t_val_r.kind(); - - then { - let sug_l = sugg::Sugg::hir(cx, val_l, ".."); - let sug_r = sugg::Sugg::hir(cx, val_r, ".."); - // format the suggestion - let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); - // spans the lint - span_lint_and_then( - cx, - FLOAT_EQUALITY_WITHOUT_ABS, - expr.span, - "float equality check without `.abs()`", - | diag | { - diag.span_suggestion( - lhs.span, - "add `.abs()`", - suggestion, - Applicability::MaybeIncorrect, - ); - } - ); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 3084c70589fa3..0aa085fc71bfe 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, - ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string", + ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, _ => false, }; let sugg = if format_args.format_string_span.contains(value.span) { diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index 647947d5d30d6..a6610ade37e56 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -1,5 +1,5 @@ use clippy_utils::{ - diagnostics::span_lint_and_sugg, + diagnostics::span_lint_hir_and_then, get_async_fn_body, is_async_fn, source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}, visitors::expr_visitor_no_bodies, @@ -43,31 +43,38 @@ declare_clippy_lint! { declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]); -fn lint_return(cx: &LateContext<'_>, span: Span) { +fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) { let mut app = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, span, "..", &mut app); - span_lint_and_sugg( + span_lint_hir_and_then( cx, IMPLICIT_RETURN, + emission_place, span, "missing `return` statement", - "add `return` as shown", - format!("return {}", snip), - app, + |diag| { + diag.span_suggestion(span, "add `return` as shown", format!("return {}", snip), app); + }, ); } -fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) { +fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, expr_span: Span) { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0; - span_lint_and_sugg( + span_lint_hir_and_then( cx, IMPLICIT_RETURN, + emission_place, break_span, "missing `return` statement", - "change `break` to `return` as shown", - format!("return {}", snip), - app, + |diag| { + diag.span_suggestion( + break_span, + "change `break` to `return` as shown", + format!("return {}", snip), + app, + ); + }, ); } @@ -152,7 +159,7 @@ fn lint_implicit_returns( // At this point sub_expr can be `None` in async functions which either diverge, or return // the unit type. if let Some(sub_expr) = sub_expr { - lint_break(cx, e.span, sub_expr.span); + lint_break(cx, e.hir_id, e.span, sub_expr.span); } } else { // the break expression is from a macro call, add a return to the loop @@ -166,10 +173,10 @@ fn lint_implicit_returns( if add_return { #[expect(clippy::option_if_let_else)] if let Some(span) = call_site_span { - lint_return(cx, span); + lint_return(cx, expr.hir_id, span); LintLocation::Parent } else { - lint_return(cx, expr.span); + lint_return(cx, expr.hir_id, expr.span); LintLocation::Inner } } else { @@ -198,10 +205,10 @@ fn lint_implicit_returns( { #[expect(clippy::option_if_let_else)] if let Some(span) = call_site_span { - lint_return(cx, span); + lint_return(cx, expr.hir_id, span); LintLocation::Parent } else { - lint_return(cx, expr.span); + lint_return(cx, expr.hir_id, expr.span); LintLocation::Inner } }, diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 78b5ec8ec1ef4..01c7eef4e04da 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{higher, match_def_path, path_def_id, paths}; -use rustc_hir::{BorrowKind, Expr, ExprKind}; +use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{sym, Symbol}; @@ -159,7 +159,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } if method.ident.name == sym!(flat_map) && args.len() == 2 { - if let ExprKind::Closure { body, .. } = args[1].kind { + if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind { let body = cx.tcx.hir().body(body); return is_infinite(cx, &body.value); } diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index 39f68a8a1b480..17d867aacb533 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method}; use if_chain::if_chain; -use rustc_hir::{ImplItem, ImplItemKind}; +use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -98,11 +98,11 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { if_chain! { // Check if item is a method, called to_string and has a parameter 'self' if let ImplItemKind::Fn(ref signature, _) = impl_item.kind; - if impl_item.ident.name.as_str() == "to_string"; + if impl_item.ident.name == sym::to_string; let decl = &signature.decl; if decl.implicit_self.has_implicit_self(); if decl.inputs.len() == 1; - if impl_item.generics.params.is_empty(); + if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })); // Check if return type is String if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String); diff --git a/src/tools/clippy/clippy_lints/src/integer_division.rs b/src/tools/clippy/clippy_lints/src/integer_division.rs deleted file mode 100644 index 3effba5682607..0000000000000 --- a/src/tools/clippy/clippy_lints/src/integer_division.rs +++ /dev/null @@ -1,61 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for division of integers - /// - /// ### Why is this bad? - /// When outside of some very specific algorithms, - /// integer division is very often a mistake because it discards the - /// remainder. - /// - /// ### Example - /// ```rust - /// let x = 3 / 2; - /// println!("{}", x); - /// ``` - /// - /// Use instead: - /// ```rust - /// let x = 3f32 / 2f32; - /// println!("{}", x); - /// ``` - #[clippy::version = "1.37.0"] - pub INTEGER_DIVISION, - restriction, - "integer division may cause loss of precision" -} - -declare_lint_pass!(IntegerDivision => [INTEGER_DIVISION]); - -impl<'tcx> LateLintPass<'tcx> for IntegerDivision { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if is_integer_division(cx, expr) { - span_lint_and_help( - cx, - INTEGER_DIVISION, - expr.span, - "integer division", - None, - "division of integers may cause loss of precision. consider using floats", - ); - } - } -} - -fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { - if_chain! { - if let hir::ExprKind::Binary(binop, left, right) = &expr.kind; - if binop.node == hir::BinOpKind::Div; - then { - let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right)); - return left_ty.is_integral() && right_ty.is_integral(); - } - } - - false -} diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 289755bfec66f..984c5cd4e37c2 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ``` /// /// Use instead: - /// ```rust.ignore + /// ```rust,ignore /// pub static a = [0u32; 1_000_000]; /// ``` #[clippy::version = "1.44.0"] diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 26c540e2223b1..176787497ebf2 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -99,12 +99,13 @@ declare_clippy_lint! { declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]); -const SYNC_GUARD_PATHS: [&[&str]; 5] = [ +const SYNC_GUARD_PATHS: [&[&str]; 6] = [ &paths::MUTEX_GUARD, &paths::RWLOCK_READ_GUARD, &paths::RWLOCK_WRITE_GUARD, - &paths::PARKING_LOT_RAWMUTEX, - &paths::PARKING_LOT_RAWRWLOCK, + &paths::PARKING_LOT_MUTEX_GUARD, + &paths::PARKING_LOT_RWLOCK_READ_GUARD, + &paths::PARKING_LOT_RWLOCK_WRITE_GUARD, ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs index 8a2cfbff953ec..563ad891603a7 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -3,12 +3,9 @@ // Manual edits will be overwritten. store.register_group(true, "clippy::all", Some("clippy_all"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assign_ops::ASSIGN_OP_PATTERN), - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(attrs::DEPRECATED_CFG_ATTR), @@ -18,8 +15,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE), LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(bit_mask::BAD_BIT_MASK), - LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), @@ -43,6 +38,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(copies::IF_SAME_THEN_ELSE), LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF), LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY), + LintId::of(dereference::EXPLICIT_AUTO_DEREF), LintId::of(dereference::NEEDLESS_BORROW), LintId::of(derivable_impls::DERIVABLE_IMPLS), LintId::of(derive::DERIVE_HASH_XOR_EQ), @@ -52,7 +49,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(double_comparison::DOUBLE_COMPARISONS), LintId::of(double_parens::DOUBLE_PARENS), LintId::of(drop_forget_ref::DROP_COPY), LintId::of(drop_forget_ref::DROP_NON_DROP), @@ -62,18 +58,13 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(drop_forget_ref::FORGET_REF), LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS), LintId::of(duplicate_mod::DUPLICATE_MOD), - LintId::of(duration_subsec::DURATION_SUBSEC), LintId::of(entry::MAP_ENTRY), LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(enum_variants::ENUM_VARIANT_NAMES), LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(eq_op::EQ_OP), - LintId::of(eq_op::OP_REF), - LintId::of(erasing_op::ERASING_OP), LintId::of(escape::BOXED_LOCAL), LintId::of(eta_reduction::REDUNDANT_CLOSURE), LintId::of(explicit_write::EXPLICIT_WRITE), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(float_literal::EXCESSIVE_PRECISION), LintId::of(format::USELESS_FORMAT), LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), @@ -93,7 +84,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::TOO_MANY_ARGUMENTS), LintId::of(get_first::GET_FIRST), - LintId::of(identity_op::IDENTITY_OP), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), @@ -118,6 +108,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(loops::FOR_KV_MAP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::MANUAL_FIND), LintId::of(loops::MANUAL_FLATTEN), LintId::of(loops::MANUAL_MEMCPY), LintId::of(loops::MISSING_SPIN_LOOP), @@ -134,6 +125,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(manual_async_fn::MANUAL_ASYNC_FN), LintId::of(manual_bits::MANUAL_BITS), LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID), + LintId::of(manual_retain::MANUAL_RETAIN), LintId::of(manual_strip::MANUAL_STRIP), LintId::of(map_clone::MAP_CLONE), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), @@ -220,9 +213,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::WRONG_SELF_CONVENTION), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), - LintId::of(misc::CMP_NAN), - LintId::of(misc::CMP_OWNED), - LintId::of(misc::MODULO_ONE), LintId::of(misc::SHORT_CIRCUIT_STATEMENT), LintId::of(misc::TOPLEVEL_REF_ARG), LintId::of(misc::ZERO_PTR), @@ -256,6 +246,23 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(octal_escapes::OCTAL_ESCAPES), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(operators::ABSURD_EXTREME_COMPARISONS), + LintId::of(operators::ASSIGN_OP_PATTERN), + LintId::of(operators::BAD_BIT_MASK), + LintId::of(operators::CMP_NAN), + LintId::of(operators::CMP_OWNED), + LintId::of(operators::DOUBLE_COMPARISONS), + LintId::of(operators::DURATION_SUBSEC), + LintId::of(operators::EQ_OP), + LintId::of(operators::ERASING_OP), + LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(operators::IDENTITY_OP), + LintId::of(operators::INEFFECTIVE_BIT_MASK), + LintId::of(operators::MISREFACTORED_ASSIGN_OP), + LintId::of(operators::MODULO_ONE), + LintId::of(operators::OP_REF), + LintId::of(operators::PTR_EQ), + LintId::of(operators::SELF_ASSIGNMENT), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), @@ -264,7 +271,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(ptr::INVALID_NULL_PTR_USAGE), LintId::of(ptr::MUT_FROM_REF), LintId::of(ptr::PTR_ARG), - LintId::of(ptr_eq::PTR_EQ), LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(question_mark::QUESTION_MARK), LintId::of(ranges::MANUAL_RANGE_CONTAINS), @@ -282,7 +288,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(repeat_once::REPEAT_ONCE), LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), - LintId::of(self_assignment::SELF_ASSIGNMENT), LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs index 4f1c3673f853c..3784d3c68dcee 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs @@ -9,21 +9,21 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::UNNECESSARY_CAST), + LintId::of(dereference::EXPLICIT_AUTO_DEREF), LintId::of(derivable_impls::DERIVABLE_IMPLS), - LintId::of(double_comparison::DOUBLE_COMPARISONS), LintId::of(double_parens::DOUBLE_PARENS), - LintId::of(duration_subsec::DURATION_SUBSEC), LintId::of(explicit_write::EXPLICIT_WRITE), LintId::of(format::USELESS_FORMAT), LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(identity_op::IDENTITY_OP), LintId::of(int_plus_one::INT_PLUS_ONE), LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(lifetimes::NEEDLESS_LIFETIMES), LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::MANUAL_FIND), LintId::of(loops::MANUAL_FLATTEN), LintId::of(loops::SINGLE_ELEMENT_LOOP), LintId::of(loops::WHILE_LET_LOOP), + LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID), LintId::of(manual_strip::MANUAL_STRIP), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), @@ -69,6 +69,9 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), LintId::of(no_effect::NO_EFFECT), LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(operators::DOUBLE_COMPARISONS), + LintId::of(operators::DURATION_SUBSEC), + LintId::of(operators::IDENTITY_OP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs index 92a3a0aabf1ca..7d5e65cb27a1f 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs @@ -3,14 +3,11 @@ // Manual edits will be overwritten. store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::DEPRECATED_SEMVER), LintId::of(attrs::MISMATCHED_TARGET_OS), LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(bit_mask::BAD_BIT_MASK), - LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(booleans::LOGIC_BUG), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES), @@ -24,8 +21,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(drop_forget_ref::FORGET_REF), LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS), LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(eq_op::EQ_OP), - LintId::of(erasing_op::ERASING_OP), LintId::of(format_impl::RECURSIVE_FORMAT_IMPL), LintId::of(formatting::POSSIBLE_MISSING_COMMA), LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), @@ -47,17 +42,22 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), - LintId::of(misc::CMP_NAN), - LintId::of(misc::MODULO_ONE), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(operators::ABSURD_EXTREME_COMPARISONS), + LintId::of(operators::BAD_BIT_MASK), + LintId::of(operators::CMP_NAN), + LintId::of(operators::EQ_OP), + LintId::of(operators::ERASING_OP), + LintId::of(operators::INEFFECTIVE_BIT_MASK), + LintId::of(operators::MODULO_ONE), + LintId::of(operators::SELF_ASSIGNMENT), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(ptr::INVALID_NULL_PTR_USAGE), LintId::of(ptr::MUT_FROM_REF), LintId::of(ranges::REVERSED_EMPTY_RANGES), LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC), LintId::of(regex::INVALID_REGEX), - LintId::of(self_assignment::SELF_ASSIGNMENT), LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(swap::ALMOST_SWAPPED), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs index 4778f4fdfa76c..be63646a12f51 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs @@ -6,6 +6,7 @@ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL), LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS), + LintId::of(utils::internal_lints::DEFAULT_DEPRECATION_REASON), LintId::of(utils::internal_lints::DEFAULT_LINT), LintId::of(utils::internal_lints::IF_CHAIN_STYLE), LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs index 8ad984c68b8ec..d3c75f8b51910 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs @@ -10,6 +10,8 @@ store.register_lints(&[ #[cfg(feature = "internal")] utils::internal_lints::COMPILER_LINT_FUNCTIONS, #[cfg(feature = "internal")] + utils::internal_lints::DEFAULT_DEPRECATION_REASON, + #[cfg(feature = "internal")] utils::internal_lints::DEFAULT_LINT, #[cfg(feature = "internal")] utils::internal_lints::IF_CHAIN_STYLE, @@ -33,7 +35,6 @@ store.register_lints(&[ utils::internal_lints::PRODUCE_ICE, #[cfg(feature = "internal")] utils::internal_lints::UNNECESSARY_SYMBOL_STR, - absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, as_conversions::AS_CONVERSIONS, @@ -41,8 +42,6 @@ store.register_lints(&[ asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - assign_ops::ASSIGN_OP_PATTERN, - assign_ops::MISREFACTORED_ASSIGN_OP, async_yields_async::ASYNC_YIELDS_ASYNC, attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON, attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, @@ -55,9 +54,6 @@ store.register_lints(&[ await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE, await_holding_invalid::AWAIT_HOLDING_LOCK, await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - bit_mask::VERBOSE_BIT_MASK, blacklisted_name::BLACKLISTED_NAME, blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, bool_assert_comparison::BOOL_ASSERT_COMPARISON, @@ -105,8 +101,10 @@ store.register_lints(&[ dbg_macro::DBG_MACRO, default::DEFAULT_TRAIT_ACCESS, default::FIELD_REASSIGN_WITH_DEFAULT, + default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY, default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, default_union_representation::DEFAULT_UNION_REPRESENTATION, + dereference::EXPLICIT_AUTO_DEREF, dereference::EXPLICIT_DEREF_METHODS, dereference::NEEDLESS_BORROW, dereference::REF_BINDING_TO_REFERENCE, @@ -125,7 +123,6 @@ store.register_lints(&[ doc::MISSING_SAFETY_DOC, doc::NEEDLESS_DOCTEST_MAIN, doc_link_with_quotes::DOC_LINK_WITH_QUOTES, - double_comparison::DOUBLE_COMPARISONS, double_parens::DOUBLE_PARENS, drop_forget_ref::DROP_COPY, drop_forget_ref::DROP_NON_DROP, @@ -135,7 +132,6 @@ store.register_lints(&[ drop_forget_ref::FORGET_REF, drop_forget_ref::UNDROPPED_MANUALLY_DROPS, duplicate_mod::DUPLICATE_MOD, - duration_subsec::DURATION_SUBSEC, else_if_without_else::ELSE_IF_WITHOUT_ELSE, empty_drop::EMPTY_DROP, empty_enum::EMPTY_ENUM, @@ -145,10 +141,7 @@ store.register_lints(&[ enum_variants::ENUM_VARIANT_NAMES, enum_variants::MODULE_INCEPTION, enum_variants::MODULE_NAME_REPETITIONS, - eq_op::EQ_OP, - eq_op::OP_REF, equatable_if_let::EQUATABLE_IF_LET, - erasing_op::ERASING_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, @@ -159,7 +152,6 @@ store.register_lints(&[ exit::EXIT, explicit_write::EXPLICIT_WRITE, fallible_impl_from::FALLIBLE_IMPL_FROM, - float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, float_literal::EXCESSIVE_PRECISION, float_literal::LOSSY_FLOAT_LITERAL, floating_point_arithmetic::IMPRECISE_FLOPS, @@ -185,7 +177,6 @@ store.register_lints(&[ functions::TOO_MANY_LINES, future_not_send::FUTURE_NOT_SEND, get_first::GET_FIRST, - identity_op::IDENTITY_OP, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, @@ -204,7 +195,6 @@ store.register_lints(&[ init_numbered_fields::INIT_NUMBERED_FIELDS, inline_fn_without_body::INLINE_FN_WITHOUT_BODY, int_plus_one::INT_PLUS_ONE, - integer_division::INTEGER_DIVISION, invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, @@ -234,6 +224,7 @@ store.register_lints(&[ loops::FOR_KV_MAP, loops::FOR_LOOPS_OVER_FALLIBLES, loops::ITER_NEXT_LOOP, + loops::MANUAL_FIND, loops::MANUAL_FLATTEN, loops::MANUAL_MEMCPY, loops::MISSING_SPIN_LOOP, @@ -253,6 +244,8 @@ store.register_lints(&[ manual_bits::MANUAL_BITS, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, manual_ok_or::MANUAL_OK_OR, + manual_rem_euclid::MANUAL_REM_EUCLID, + manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, map_clone::MAP_CLONE, map_err_ignore::MAP_ERR_IGNORE, @@ -364,11 +357,6 @@ store.register_lints(&[ methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, - misc::CMP_NAN, - misc::CMP_OWNED, - misc::FLOAT_CMP, - misc::FLOAT_CMP_CONST, - misc::MODULO_ONE, misc::SHORT_CIRCUIT_STATEMENT, misc::TOPLEVEL_REF_ARG, misc::USED_UNDERSCORE_BINDING, @@ -392,7 +380,6 @@ store.register_lints(&[ mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION, module_style::MOD_MODULE_FILES, module_style::SELF_NAMED_MODULE_FILES, - modulo_arithmetic::MODULO_ARITHMETIC, mut_key::MUTABLE_KEY_TYPE, mut_mut::MUT_MUT, mut_mutex_lock::MUT_MUTEX_LOCK, @@ -401,7 +388,6 @@ store.register_lints(&[ mutex_atomic::MUTEX_ATOMIC, mutex_atomic::MUTEX_INTEGER, needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, - needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, @@ -426,11 +412,34 @@ store.register_lints(&[ non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY, nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, - numeric_arithmetic::FLOAT_ARITHMETIC, - numeric_arithmetic::INTEGER_ARITHMETIC, octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, open_options::NONSENSICAL_OPEN_OPTIONS, + operators::ABSURD_EXTREME_COMPARISONS, + operators::ASSIGN_OP_PATTERN, + operators::BAD_BIT_MASK, + operators::CMP_NAN, + operators::CMP_OWNED, + operators::DOUBLE_COMPARISONS, + operators::DURATION_SUBSEC, + operators::EQ_OP, + operators::ERASING_OP, + operators::FLOAT_ARITHMETIC, + operators::FLOAT_CMP, + operators::FLOAT_CMP_CONST, + operators::FLOAT_EQUALITY_WITHOUT_ABS, + operators::IDENTITY_OP, + operators::INEFFECTIVE_BIT_MASK, + operators::INTEGER_ARITHMETIC, + operators::INTEGER_DIVISION, + operators::MISREFACTORED_ASSIGN_OP, + operators::MODULO_ARITHMETIC, + operators::MODULO_ONE, + operators::NEEDLESS_BITWISE_BOOL, + operators::OP_REF, + operators::PTR_EQ, + operators::SELF_ASSIGNMENT, + operators::VERBOSE_BIT_MASK, option_env_unwrap::OPTION_ENV_UNWRAP, option_if_let_else::OPTION_IF_LET_ELSE, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, @@ -449,7 +458,6 @@ store.register_lints(&[ ptr::INVALID_NULL_PTR_USAGE, ptr::MUT_FROM_REF, ptr::PTR_ARG, - ptr_eq::PTR_EQ, ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, pub_use::PUB_USE, question_mark::QUESTION_MARK, @@ -477,7 +485,6 @@ store.register_lints(&[ returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, same_name_method::SAME_NAME_METHOD, - self_assignment::SELF_ASSIGNMENT, self_named_constructors::SELF_NAMED_CONSTRUCTORS, semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, serde_api::SERDE_API_MISUSE, diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs index 48de92ae94523..a1b5466581491 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(bit_mask::VERBOSE_BIT_MASK), LintId::of(borrow_as_ptr::BORROW_AS_PTR), LintId::of(bytecount::NAIVE_BYTECOUNT), LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), @@ -65,17 +64,18 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::INEFFICIENT_TO_STRING), LintId::of(methods::MAP_UNWRAP_OR), LintId::of(methods::UNNECESSARY_JOIN), - LintId::of(misc::FLOAT_CMP), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER), LintId::of(mut_mut::MUT_MUT), - LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), LintId::of(needless_continue::NEEDLESS_CONTINUE), LintId::of(needless_for_each::NEEDLESS_FOR_EACH), LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING), LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), LintId::of(non_expressive_names::SIMILAR_NAMES), + LintId::of(operators::FLOAT_CMP), + LintId::of(operators::NEEDLESS_BITWISE_BOOL), + LintId::of(operators::VERBOSE_BIT_MASK), LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(ranges::RANGE_MINUS_ONE), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs index 82431863e6cfd..6bf519c24e848 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs @@ -13,6 +13,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(loops::MANUAL_MEMCPY), LintId::of(loops::MISSING_SPIN_LOOP), LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(manual_retain::MANUAL_RETAIN), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::ITER_NTH), @@ -21,7 +22,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(methods::OR_FUN_CALL), LintId::of(methods::SINGLE_CHAR_PATTERN), LintId::of(methods::UNNECESSARY_TO_OWNED), - LintId::of(misc::CMP_OWNED), + LintId::of(operators::CMP_OWNED), LintId::of(redundant_clone::REDUNDANT_CLONE), LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(types::BOX_COLLECTION), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs index 3695012f55238..970e9db4772cb 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs @@ -25,7 +25,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(implicit_return::IMPLICIT_RETURN), LintId::of(indexing_slicing::INDEXING_SLICING), LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), - LintId::of(integer_division::INTEGER_DIVISION), LintId::of(large_include_file::LARGE_INCLUDE_FILE), LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), @@ -39,7 +38,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::FILETYPE_IS_FILE), LintId::of(methods::GET_UNWRAP), LintId::of(methods::UNWRAP_USED), - LintId::of(misc::FLOAT_CMP_CONST), LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), @@ -49,9 +47,11 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION), LintId::of(module_style::MOD_MODULE_FILES), LintId::of(module_style::SELF_NAMED_MODULE_FILES), - LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), - LintId::of(numeric_arithmetic::FLOAT_ARITHMETIC), - LintId::of(numeric_arithmetic::INTEGER_ARITHMETIC), + LintId::of(operators::FLOAT_ARITHMETIC), + LintId::of(operators::FLOAT_CMP_CONST), + LintId::of(operators::INTEGER_ARITHMETIC), + LintId::of(operators::INTEGER_DIVISION), + LintId::of(operators::MODULO_ARITHMETIC), LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), LintId::of(panic_unimplemented::PANIC), LintId::of(panic_unimplemented::TODO), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs index b6992ae0ad25f..15a1bc569af23 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assign_ops::ASSIGN_OP_PATTERN), LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), @@ -14,6 +13,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(collapsible_if::COLLAPSIBLE_IF), LintId::of(comparison_chain::COMPARISON_CHAIN), LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY), LintId::of(dereference::NEEDLESS_BORROW), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), @@ -22,7 +22,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(doc::NEEDLESS_DOCTEST_MAIN), LintId::of(enum_variants::ENUM_VARIANT_NAMES), LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(eq_op::OP_REF), LintId::of(eta_reduction::REDUNDANT_CLOSURE), LintId::of(float_literal::EXCESSIVE_PRECISION), LintId::of(from_over_into::FROM_OVER_INTO), @@ -97,9 +96,11 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(operators::ASSIGN_OP_PATTERN), + LintId::of(operators::OP_REF), + LintId::of(operators::PTR_EQ), LintId::of(ptr::CMP_NULL), LintId::of(ptr::PTR_ARG), - LintId::of(ptr_eq::PTR_EQ), LintId::of(question_mark::QUESTION_MARK), LintId::of(ranges::MANUAL_RANGE_CONTAINS), LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs index 7b13713c36e59..f7558f8709810 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![ LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE), LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), @@ -16,7 +15,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(drop_forget_ref::DROP_NON_DROP), LintId::of(drop_forget_ref::FORGET_NON_DROP), LintId::of(duplicate_mod::DUPLICATE_MOD), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(format_impl::PRINT_IN_FORMAT_IMPL), LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), @@ -29,6 +27,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(octal_escapes::OCTAL_ESCAPES), + LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(operators::MISREFACTORED_ASSIGN_OP), LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT), LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 84898eae05ac4..884baaea02926 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -4,9 +4,10 @@ #![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(iter_intersperse)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(lint_reasons)] +#![feature(never_type)] #![feature(once_cell)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] @@ -52,6 +53,7 @@ extern crate clippy_utils; use clippy_utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; +use rustc_semver::RustcVersion; use rustc_session::Session; /// Macro used to declare a Clippy lint. @@ -159,25 +161,22 @@ macro_rules! declare_clippy_lint { } #[cfg(feature = "internal")] -mod deprecated_lints; +pub mod deprecated_lints; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` -mod absurd_extreme_comparisons; mod almost_complete_letter_range; mod approx_const; mod as_conversions; mod as_underscore; mod asm_syntax; mod assertions_on_constants; -mod assign_ops; mod async_yields_async; mod attrs; mod await_holding_invalid; -mod bit_mask; mod blacklisted_name; mod blocks_in_if_conditions; mod bool_assert_comparison; @@ -199,6 +198,7 @@ mod crate_in_macro_def; mod create_dir; mod dbg_macro; mod default; +mod default_instead_of_iter_empty; mod default_numeric_fallback; mod default_union_representation; mod dereference; @@ -209,11 +209,9 @@ mod disallowed_script_idents; mod disallowed_types; mod doc; mod doc_link_with_quotes; -mod double_comparison; mod double_parens; mod drop_forget_ref; mod duplicate_mod; -mod duration_subsec; mod else_if_without_else; mod empty_drop; mod empty_enum; @@ -221,9 +219,7 @@ mod empty_structs_with_brackets; mod entry; mod enum_clike; mod enum_variants; -mod eq_op; mod equatable_if_let; -mod erasing_op; mod escape; mod eta_reduction; mod excessive_bools; @@ -231,7 +227,6 @@ mod exhaustive_items; mod exit; mod explicit_write; mod fallible_impl_from; -mod float_equality_without_abs; mod float_literal; mod floating_point_arithmetic; mod format; @@ -244,7 +239,6 @@ mod from_str_radix_10; mod functions; mod future_not_send; mod get_first; -mod identity_op; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -260,7 +254,6 @@ mod inherent_to_string; mod init_numbered_fields; mod inline_fn_without_body; mod int_plus_one; -mod integer_division; mod invalid_upcast_comparisons; mod items_after_statements; mod iter_not_returning_iterator; @@ -281,6 +274,8 @@ mod manual_async_fn; mod manual_bits; mod manual_non_exhaustive; mod manual_ok_or; +mod manual_rem_euclid; +mod manual_retain; mod manual_strip; mod map_clone; mod map_err_ignore; @@ -300,7 +295,6 @@ mod missing_enforced_import_rename; mod missing_inline; mod mixed_read_write_in_expression; mod module_style; -mod modulo_arithmetic; mod mut_key; mod mut_mut; mod mut_mutex_lock; @@ -308,7 +302,6 @@ mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; mod needless_arbitrary_self_type; -mod needless_bitwise_bool; mod needless_bool; mod needless_borrowed_ref; mod needless_continue; @@ -327,10 +320,10 @@ mod non_expressive_names; mod non_octal_unix_permissions; mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; -mod numeric_arithmetic; mod octal_escapes; mod only_used_in_recursion; mod open_options; +mod operators; mod option_env_unwrap; mod option_if_let_else; mod overflow_check_conditional; @@ -342,7 +335,6 @@ mod path_buf_push_overwrite; mod pattern_type_mismatch; mod precedence; mod ptr; -mod ptr_eq; mod ptr_offset_with_cast; mod pub_use; mod question_mark; @@ -363,7 +355,6 @@ mod repeat_once; mod return_self_not_must_use; mod returns; mod same_name_method; -mod self_assignment; mod self_named_constructors; mod semicolon_if_nothing_returned; mod serde_api; @@ -448,6 +439,39 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv })); } +fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> { + let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") + .ok() + .and_then(|v| parse_msrv(&v, None, None)); + let clippy_msrv = conf.msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(&format!( + "error reading Clippy's configuration file. `{}` is not a valid Rust version", + s + )); + None + }) + }); + + if let Some(cargo_msrv) = cargo_msrv { + if let Some(clippy_msrv) = clippy_msrv { + // if both files have an msrv, let's compare them and emit a warning if they differ + if clippy_msrv != cargo_msrv { + sess.warn(&format!( + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{}` from `clippy.toml`", + clippy_msrv + )); + } + + Some(clippy_msrv) + } else { + Some(cargo_msrv) + } + } else { + clippy_msrv + } +} + #[doc(hidden)] pub fn read_conf(sess: &Session) -> Conf { let file_name = match utils::conf::lookup_conf_file() { @@ -463,12 +487,11 @@ pub fn read_conf(sess: &Session) -> Conf { let TryConf { conf, errors } = utils::conf::read(&file_name); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { - sess.struct_err(&format!( + sess.err(&format!( "error reading Clippy's configuration file `{}`: {}", file_name.display(), format_error(error) - )) - .emit(); + )); } conf @@ -543,21 +566,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); store.register_late_pass(|| Box::new(booleans::NonminimalBool)); - store.register_late_pass(|| Box::new(needless_bitwise_bool::NeedlessBitwiseBool)); - store.register_late_pass(|| Box::new(eq_op::EqOp)); store.register_late_pass(|| Box::new(enum_clike::UnportableVariant)); store.register_late_pass(|| Box::new(float_literal::FloatLiteral)); - let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; - store.register_late_pass(move || Box::new(bit_mask::BitMask::new(verbose_bit_mask_threshold))); store.register_late_pass(|| Box::new(ptr::Ptr)); - store.register_late_pass(|| Box::new(ptr_eq::PtrEq)); store.register_late_pass(|| Box::new(needless_bool::NeedlessBool)); store.register_late_pass(|| Box::new(needless_bool::BoolComparison)); store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach)); store.register_late_pass(|| Box::new(misc::MiscLints)); store.register_late_pass(|| Box::new(eta_reduction::EtaReduction)); - store.register_late_pass(|| Box::new(identity_op::IdentityOp)); - store.register_late_pass(|| Box::new(erasing_op::ErasingOp)); store.register_late_pass(|| Box::new(mut_mut::MutMut)); store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed)); store.register_late_pass(|| Box::new(len_zero::LenZero)); @@ -575,16 +591,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); - let msrv = conf.msrv.as_ref().and_then(|s| { - parse_msrv(s, None, None).or_else(|| { - sess.err(&format!( - "error reading Clippy's configuration file. `{}` is not a valid Rust version", - s - )); - None - }) - }); - + let msrv = read_msrv(conf, sess); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; @@ -639,7 +646,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef)); store.register_late_pass(|| Box::new(no_effect::NoEffect)); store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment)); - store.register_late_pass(|| Box::new(transmute::Transmute)); + store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv))); let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; store.register_late_pass(move || { Box::new(cognitive_complexity::CognitiveComplexity::new( @@ -655,7 +662,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls)); store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|| Box::new(empty_enum::EmptyEnum)); - store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons)); 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)); @@ -678,8 +684,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); store.register_late_pass(|| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|| Box::new(mem_forget::MemForget)); - store.register_late_pass(|| Box::new(numeric_arithmetic::NumericArithmetic::default())); - store.register_late_pass(|| Box::new(assign_ops::AssignOps)); store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new())); @@ -706,7 +710,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher)); store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom)); - store.register_late_pass(|| Box::new(double_comparison::DoubleComparisons)); store.register_late_pass(|| Box::new(question_mark::QuestionMark)); store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)); store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl)); @@ -714,7 +717,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl)); store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd)); store.register_late_pass(|| Box::new(unwrap::Unwrap)); - store.register_late_pass(|| Box::new(duration_subsec::DurationSubsec)); store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing)); store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst)); store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); @@ -725,13 +727,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); - store.register_late_pass(|| Box::new(integer_division::IntegerDivision)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain)); store.register_late_pass(|| Box::new(mut_key::MutableKeyType)); - store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic)); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); store.register_late_pass(|| Box::new(format_impl::FormatImpl::new())); @@ -828,9 +828,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); store.register_late_pass(|| Box::new(repeat_once::RepeatOnce)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); - store.register_late_pass(|| Box::new(self_assignment::SelfAssignment)); store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr)); - store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); let disallowed_methods = conf.disallowed_methods.clone(); @@ -910,6 +908,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch)); store.register_late_pass(|| Box::new(as_underscore::AsUnderscore)); store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec)); + store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); + store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); + store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv))); + let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; + store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 93f5663312f2e..083c437a293c0 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -9,8 +9,8 @@ use rustc_hir::intravisit::{ use rustc_hir::FnRetTy::Return; use rustc_hir::{ BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem, - ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, - TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, + ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef, + PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter as middle_nested_filter; @@ -92,7 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { if let ItemKind::Fn(ref sig, generics, id) = item.kind { check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true); } else if let ItemKind::Impl(impl_) = item.kind { - report_extra_impl_lifetimes(cx, impl_); + if !item.span.from_expansion() { + report_extra_impl_lifetimes(cx, impl_); + } } } @@ -336,7 +338,10 @@ fn could_use_elision<'tcx>( fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> { let mut allowed_lts = FxHashSet::default(); for par in named_generics.iter() { - if let GenericParamKind::Lifetime { .. } = par.kind { + if let GenericParamKind::Lifetime { + kind: LifetimeParamKind::Explicit, + } = par.kind + { allowed_lts.insert(RefLt::Named(par.name.ident().name)); } } @@ -377,6 +382,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { self.lts.push(RefLt::Static); } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name { // Fresh lifetimes generated should be ignored. + self.lts.push(RefLt::Unnamed); } else if lt.is_elided() { self.lts.push(RefLt::Unnamed); } else { diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs new file mode 100644 index 0000000000000..33736d6d4e650 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -0,0 +1,158 @@ +use super::utils::make_iterator_snippet; +use super::MANUAL_FIND; +use clippy_utils::{ + diagnostics::span_lint_and_then, higher, is_lang_ctor, path_res, peel_blocks_with_stmt, + source::snippet_with_applicability, ty::implements_trait, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{ + def::Res, lang_items::LangItem, BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind, +}; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + span: Span, + expr: &'tcx Expr<'_>, +) { + let inner_expr = peel_blocks_with_stmt(body); + // Check for the specific case that the result is returned and optimize suggestion for that (more + // cases can be added later) + if_chain! { + if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr); + if let Some(binding_id) = get_binding(pat); + if let ExprKind::Block(block, _) = then.kind; + if let [stmt] = block.stmts; + if let StmtKind::Semi(semi) = stmt.kind; + if let ExprKind::Ret(Some(ret_value)) = semi.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ctor), .. }, [inner_ret]) = ret_value.kind; + if is_lang_ctor(cx, ctor, LangItem::OptionSome); + if path_res(cx, inner_ret) == Res::Local(binding_id); + if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr); + then { + let mut applicability = Applicability::MachineApplicable; + let mut snippet = make_iterator_snippet(cx, arg, &mut applicability); + // Checks if `pat` is a single reference to a binding (`&x`) + let is_ref_to_binding = + matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..))); + // If `pat` is not a binding or a reference to a binding (`x` or `&x`) + // we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`) + if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) { + snippet.push_str( + &format!( + ".map(|{}| {})", + snippet_with_applicability(cx, pat.span, "..", &mut applicability), + snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), + )[..], + ); + } + let ty = cx.typeck_results().expr_ty(inner_ret); + if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) { + snippet.push_str( + &format!( + ".find(|{}{}| {})", + "&".repeat(1 + usize::from(is_ref_to_binding)), + snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), + snippet_with_applicability(cx, cond.span, "..", &mut applicability), + )[..], + ); + if is_ref_to_binding { + snippet.push_str(".copied()"); + } + } else { + applicability = Applicability::MaybeIncorrect; + snippet.push_str( + &format!( + ".find(|{}| {})", + snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability), + snippet_with_applicability(cx, cond.span, "..", &mut applicability), + )[..], + ); + } + // Extends to `last_stmt` to include semicolon in case of `return None;` + let lint_span = span.to(last_stmt.span).to(last_ret.span); + span_lint_and_then( + cx, + MANUAL_FIND, + lint_span, + "manual implementation of `Iterator::find`", + |diag| { + if applicability == Applicability::MaybeIncorrect { + diag.note("you may need to dereference some variables"); + } + diag.span_suggestion( + lint_span, + "replace with an iterator", + snippet, + applicability, + ); + }, + ); + } + } +} + +fn get_binding(pat: &Pat<'_>) -> Option<HirId> { + let mut hir_id = None; + let mut count = 0; + pat.each_binding(|annotation, id, _, _| { + count += 1; + if count > 1 { + hir_id = None; + return; + } + if let BindingAnnotation::Unannotated = annotation { + hir_id = Some(id); + } + }); + hir_id +} + +// Returns the last statement and last return if function fits format for lint +fn last_stmt_and_ret<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, +) -> Option<(&'tcx Stmt<'tcx>, &'tcx Expr<'tcx>)> { + // Returns last non-return statement and the last return + fn extract<'tcx>(block: &Block<'tcx>) -> Option<(&'tcx Stmt<'tcx>, &'tcx Expr<'tcx>)> { + if let [.., last_stmt] = block.stmts { + if let Some(ret) = block.expr { + return Some((last_stmt, ret)); + } + if_chain! { + if let [.., snd_last, _] = block.stmts; + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let ExprKind::Ret(Some(ret)) = last_expr.kind; + then { + return Some((snd_last, ret)); + } + } + } + None + } + let mut parent_iter = cx.tcx.hir().parent_iter(expr.hir_id); + if_chain! { + // This should be the loop + if let Some((node_hir, Node::Stmt(..))) = parent_iter.next(); + // This should be the funciton body + if let Some((_, Node::Block(block))) = parent_iter.next(); + if let Some((last_stmt, last_ret)) = extract(block); + if last_stmt.hir_id == node_hir; + if let ExprKind::Path(path) = &last_ret.kind; + if is_lang_ctor(cx, path, LangItem::OptionNone); + if let Some((_, Node::Expr(_block))) = parent_iter.next(); + // This includes the function header + if let Some((_, func)) = parent_iter.next(); + if func.fn_kind().is_some(); + then { + Some((block.stmts.last().unwrap(), last_ret)) + } else { + None + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 391de922e1e1a..ed270bd490d78 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -5,6 +5,7 @@ mod explicit_iter_loop; mod for_kv_map; mod for_loops_over_fallibles; mod iter_next_loop; +mod manual_find; mod manual_flatten; mod manual_memcpy; mod missing_spin_loop; @@ -346,7 +347,14 @@ declare_clippy_lint! { /// /// ### Example /// ```ignore - /// while let Some(val) = iter() { + /// while let Some(val) = iter.next() { + /// .. + /// } + /// ``` + /// + /// Use instead: + /// ```ignore + /// for val in &mut iter { /// .. /// } /// ``` @@ -602,6 +610,37 @@ declare_clippy_lint! { "An empty busy waiting loop" } +declare_clippy_lint! { + /// ### What it does + /// Check for manual implementations of Iterator::find + /// + /// ### Why is this bad? + /// It doesn't affect performance, but using `find` is shorter and easier to read. + /// + /// ### Example + /// + /// ```rust + /// fn example(arr: Vec<i32>) -> Option<i32> { + /// for el in arr { + /// if el == 1 { + /// return Some(el); + /// } + /// } + /// None + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn example(arr: Vec<i32>) -> Option<i32> { + /// arr.into_iter().find(|&el| el == 1) + /// } + /// ``` + #[clippy::version = "1.61.0"] + pub MANUAL_FIND, + complexity, + "manual implementation of `Iterator::find`" +} + declare_lint_pass!(Loops => [ MANUAL_MEMCPY, MANUAL_FLATTEN, @@ -622,6 +661,7 @@ declare_lint_pass!(Loops => [ SAME_ITEM_PUSH, SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, + MANUAL_FIND, ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -696,6 +736,7 @@ fn check_for_loop<'tcx>( single_element_loop::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr); manual_flatten::check(cx, pat, arg, body, span); + manual_find::check(cx, pat, arg, body, span, expr); } fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index d20df83045589..aedf3810b23e9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -43,7 +43,7 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) { fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> { if_chain! { if let Some(hir_id) = path_to_local(bound); - if let Node::Binding(pat) = cx.tcx.hir().get(hir_id); + if let Node::Pat(pat) = cx.tcx.hir().get(hir_id); if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { return Some(hir_id); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 0b6d9adb553e4..a7ef562b21fc4 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -9,7 +9,7 @@ use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath}; +use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; @@ -369,7 +369,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { self.visit_expr(expr); } }, - ExprKind::Closure { body, .. } => { + ExprKind::Closure(&Closure { body, .. }) => { let body = self.cx.tcx.hir().body(body); self.visit_expr(&body.value); }, 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 e048d744fc3ba..1439f1f4c75d5 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 @@ -63,7 +63,7 @@ pub(super) fn check<'tcx>( Res::Local(hir_id) => { let node = cx.tcx.hir().get(hir_id); if_chain! { - if let Node::Binding(pat) = node; + if let Node::Pat(pat) = node; if let PatKind::Binding(bind_ann, ..) = pat.kind; if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); let parent_node = cx.tcx.hir().get_parent_node(hir_id); diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index 8f57df0be6bd4..ca617859db49d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -2,71 +2,60 @@ use super::WHILE_LET_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::needs_ordered_drop; +use clippy_utils::visitors::any_temporaries_need_ordered_drop; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, MatchSource, Pat, StmtKind}; -use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; +use rustc_hir::{Block, Expr, ExprKind, Local, MatchSource, Pat, StmtKind}; +use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { - // extract the expression from the first statement (if any) in a block - let inner_stmt_expr = extract_expr_from_first_stmt(loop_block); - // or extract the first expression (if any) from the block - if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(loop_block)) { - if let Some(higher::IfLet { - let_pat, - let_expr, - if_else: Some(if_else), - .. - }) = higher::IfLet::hir(cx, inner) - { - if is_simple_break_expr(if_else) { - could_be_while_let(cx, expr, let_pat, let_expr); + let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { + ([stmt, stmts @ ..], expr) => { + if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { + (e, !stmts.is_empty() || expr.is_some()) + } else { + return; } - } - - if let ExprKind::Match(matchexpr, arms, MatchSource::Normal) = inner.kind { - if arms.len() == 2 - && arms[0].guard.is_none() - && arms[1].guard.is_none() - && is_simple_break_expr(arms[1].body) - { - could_be_while_let(cx, expr, arms[0].pat, matchexpr); - } - } - } -} + }, + ([], Some(e)) => (e, false), + _ => return, + }; -/// If a block begins with a statement (possibly a `let` binding) and has an -/// expression, return it. -fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if let Some(first_stmt) = block.stmts.get(0) { - if let StmtKind::Local(local) = first_stmt.kind { - return local.init; - } + if let Some(if_let) = higher::IfLet::hir(cx, init) + && let Some(else_expr) = if_let.if_else + && is_simple_break_expr(else_expr) + { + could_be_while_let(cx, expr, if_let.let_pat, if_let.let_expr, has_trailing_exprs); + } else if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal) = init.kind + && arm1.guard.is_none() + && arm2.guard.is_none() + && is_simple_break_expr(arm2.body) + { + could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs); } - None } -/// If a block begins with an expression (with or without semicolon), return it. -fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { - match block.expr { - Some(expr) if block.stmts.is_empty() => Some(expr), - None if !block.stmts.is_empty() => match block.stmts[0].kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some(expr), - StmtKind::Local(..) | StmtKind::Item(..) => None, - }, - _ => None, - } +/// Returns `true` if expr contains a single break expression without a label or eub-expression. +fn is_simple_break_expr(e: &Expr<'_>) -> bool { + matches!(peel_blocks(e).kind, ExprKind::Break(dest, None) if dest.label.is_none()) } -/// Returns `true` if expr contains a single break expr without destination label -/// and -/// passed expression. The expression may be within a block. -fn is_simple_break_expr(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true, - ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, is_simple_break_expr), - _ => false, +/// Removes any blocks containing only a single expression. +fn peel_blocks<'tcx>(e: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { + if let ExprKind::Block(b, _) = e.kind { + match (b.stmts, b.expr) { + ([s], None) => { + if let StmtKind::Expr(e) | StmtKind::Semi(e) = s.kind { + peel_blocks(e) + } else { + e + } + }, + ([], Some(e)) => peel_blocks(e), + _ => e, + } + } else { + e } } @@ -75,8 +64,13 @@ fn could_be_while_let<'tcx>( expr: &'tcx Expr<'_>, let_pat: &'tcx Pat<'_>, let_expr: &'tcx Expr<'_>, + has_trailing_exprs: bool, ) { - if in_external_macro(cx.sess(), expr.span) { + if has_trailing_exprs + && (needs_ordered_drop(cx, cx.typeck_results().expr_ty(let_expr)) + || any_temporaries_need_ordered_drop(cx, let_expr)) + { + // Switching to a `while let` loop will extend the lifetime of some values. return; } diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index a57159750664f..b94bbd2bd417d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -8,7 +8,7 @@ use clippy_utils::{ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; +use rustc_hir::{Closure, def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::{symbol::sym, Symbol}; @@ -220,7 +220,7 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc if let Some(e) = e { self.visit_expr(e); } - } else if let ExprKind::Closure { body: id, .. } = e.kind { + } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind { if is_res_used(self.cx, self.iter_expr.path, id) { self.uses_iter = true; } @@ -260,7 +260,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & if let Some(e) = e { self.visit_expr(e); } - } else if let ExprKind::Closure { body: id, .. } = e.kind { + } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind { self.used_iter = is_res_used(self.cx, self.iter_expr.path, id); } else { walk_expr(self, e); @@ -307,7 +307,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & if let Some(e) = e { self.visit_expr(e); } - } else if let ExprKind::Closure { body: id, .. } = e.kind { + } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind { self.used_after = is_res_used(self.cx, self.iter_expr.path, id); } else { walk_expr(self, e); diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 753469c603d40..d573a1b4fbb5d 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use if_chain::if_chain; @@ -50,8 +50,9 @@ impl MacroRefData { #[derive(Default)] #[expect(clippy::module_name_repetitions)] pub struct MacroUseImports { - /// the actual import path used and the span of the attribute above it. - imports: Vec<(String, Span)>, + /// the actual import path used and the span of the attribute above it. The value is + /// the location, where the lint should be emitted. + imports: Vec<(String, Span, hir::HirId)>, /// the span of the macro reference, kept to ensure only one reference is used per macro call. collected: FxHashSet<Span>, mac_refs: Vec<MacroRefData>, @@ -90,7 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { if_chain! { if cx.sess().opts.edition >= Edition::Edition2018; if let hir::ItemKind::Use(path, _kind) = &item.kind; - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let hir_id = item.hir_id(); + let attrs = cx.tcx.hir().attrs(hir_id); if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)); if let Res::Def(DefKind::Mod, id) = path.res; if !id.is_local(); @@ -99,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { let span = mac_attr.span; let def_path = cx.tcx.def_path_str(mac_id); - self.imports.push((def_path, span)); + self.imports.push((def_path, span, hir_id)); } } } else { @@ -137,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { fn check_crate_post(&mut self, cx: &LateContext<'_>) { let mut used = FxHashMap::default(); let mut check_dup = vec![]; - for (import, span) in &self.imports { + for (import, span, hir_id) in &self.imports { let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name)); if let Some(idx) = found_idx { @@ -150,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { [] | [_] => return, [root, item] => { if !check_dup.contains(&(*item).to_string()) { - used.entry(((*root).to_string(), span)) + used.entry(((*root).to_string(), span, hir_id)) .or_insert_with(Vec::new) .push((*item).to_string()); check_dup.push((*item).to_string()); @@ -168,13 +170,13 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } }) .collect::<Vec<_>>(); - used.entry(((*root).to_string(), span)) + used.entry(((*root).to_string(), span, hir_id)) .or_insert_with(Vec::new) .push(filtered.join("::")); check_dup.extend(filtered); } else { let rest = rest.to_vec(); - used.entry(((*root).to_string(), span)) + used.entry(((*root).to_string(), span, hir_id)) .or_insert_with(Vec::new) .push(rest.join("::")); check_dup.extend(rest.iter().map(ToString::to_string)); @@ -185,27 +187,33 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } let mut suggestions = vec![]; - for ((root, span), path) in used { + for ((root, span, hir_id), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]))); + suggestions.push((span, format!("{}::{}", root, path[0]), hir_id)); } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))); + suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")), hir_id)); } } // If mac_refs is not empty we have encountered an import we could not handle // such as `std::prelude::v1::foo` or some other macro that expands to an import. if self.mac_refs.is_empty() { - for (span, import) in suggestions { + for (span, import, hir_id) in suggestions { let help = format!("use {};", import); - span_lint_and_sugg( + span_lint_hir_and_then( cx, MACRO_USE_IMPORTS, + *hir_id, *span, "`macro_use` attributes are no longer needed in the Rust 2018 edition", - "remove the attribute and import the macro directly, try", - help, - Applicability::MaybeIncorrect, + |diag| { + diag.span_suggestion( + *span, + "remove the attribute and import the macro directly, try", + help, + Applicability::MaybeIncorrect, + ); + }, ); } } 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 d7d8a59215280..93a34f452f6d6 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId, + AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId, IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -177,7 +177,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) if let Some(block_expr) = block.expr; if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR); if args.len() == 1; - if let Expr{kind: ExprKind::Closure { body, .. }, ..} = args[0]; + if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0]; let closure_body = cx.tcx.hir().body(body); if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); then { diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 14f5faafd7cb9..4278e98dc91fa 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -1,6 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; -use clippy_utils::{is_doc_hidden, is_lint_allowed, meets_msrv, msrvs}; +use clippy_utils::{is_doc_hidden, meets_msrv, msrvs}; use rustc_ast::ast::{self, VisibilityKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -190,12 +190,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { !self .constructed_enum_variants .contains(&(enum_id.to_def_id(), variant_id.to_def_id())) - && !is_lint_allowed(cx, MANUAL_NON_EXHAUSTIVE, cx.tcx.hir().local_def_id_to_hir_id(enum_id)) }) { - span_lint_and_then( + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(enum_id); + span_lint_hir_and_then( cx, MANUAL_NON_EXHAUSTIVE, + hir_id, enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs index 18cfd00376784..9abf2507b921c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_lang_ctor, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Expr, ExprKind, PatKind}; +use rustc_hir::{Closure, Expr, ExprKind, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -88,7 +88,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { } } if_chain! { - if let ExprKind::Closure { body, .. } = map_expr.kind; + if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; let body = cx.tcx.hir().body(body); if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs new file mode 100644 index 0000000000000..2ce9d0e77c1fd --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -0,0 +1,122 @@ +use clippy_utils::consts::{constant_full_int, FullInt}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{in_constant, meets_msrv, msrvs, path_to_local}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation + /// of `x.rem_euclid(4)`. + /// + /// ### Why is this bad? + /// It's simpler and more readable. + /// + /// ### Example + /// ```rust + /// let x: i32 = 24; + /// let rem = ((x % 4) + 4) % 4; + /// ``` + /// Use instead: + /// ```rust + /// let x: i32 = 24; + /// let rem = x.rem_euclid(4); + /// ``` + #[clippy::version = "1.63.0"] + pub MANUAL_REM_EUCLID, + complexity, + "manually reimplementing `rem_euclid`" +} + +pub struct ManualRemEuclid { + msrv: Option<RustcVersion>, +} + +impl ManualRemEuclid { + #[must_use] + pub fn new(msrv: Option<RustcVersion>) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]); + +impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !meets_msrv(self.msrv, msrvs::REM_EUCLID) { + return; + } + + if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::REM_EUCLID_CONST) { + return; + } + + if in_external_macro(cx.sess(), expr.span) { + return; + } + + if let ExprKind::Binary(op1, expr1, right) = expr.kind + && op1.node == BinOpKind::Rem + && let Some(const1) = check_for_unsigned_int_constant(cx, right) + && let ExprKind::Binary(op2, left, right) = expr1.kind + && op2.node == BinOpKind::Add + && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right) + && let ExprKind::Binary(op3, expr3, right) = expr2.kind + && op3.node == BinOpKind::Rem + && let Some(const3) = check_for_unsigned_int_constant(cx, right) + // Also ensures the const is nonzero since zero can't be a divisor + && const1 == const2 && const2 == const3 + && let Some(hir_id) = path_to_local(expr3) { + // Apply only to params or locals with annotated types + match cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + Some(Node::Param(..)) => (), + Some(Node::Local(local)) => { + let Some(ty) = local.ty else { return }; + if matches!(ty.kind, TyKind::Infer) { + return; + } + } + _ => return, + }; + + let mut app = Applicability::MachineApplicable; + let rem_of = snippet_with_applicability(cx, expr3.span, "_", &mut app); + span_lint_and_sugg( + cx, + MANUAL_REM_EUCLID, + expr.span, + "manual `rem_euclid` implementation", + "consider using", + format!("{rem_of}.rem_euclid({const1})"), + app, + ); + } + } + + extract_msrv_attr!(LateContext); +} + +// Checks if either the left or right expressions can be an unsigned int constant and returns that +// constant along with the other expression unchanged if so +fn check_for_either_unsigned_int_constant<'a>( + cx: &'a LateContext<'_>, + left: &'a Expr<'_>, + right: &'a Expr<'_>, +) -> Option<(u128, &'a Expr<'a>)> { + check_for_unsigned_int_constant(cx, left) + .map(|int_const| (int_const, right)) + .or_else(|| check_for_unsigned_int_constant(cx, right).map(|int_const| (int_const, left))) +} + +fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> { + let Some(int_const) = constant_full_int(cx, cx.typeck_results(), expr) else { return None }; + match int_const { + FullInt::S(s) => s.try_into().ok(), + FullInt::U(u) => Some(u), + } +} diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs new file mode 100644 index 0000000000000..42d2577cc3161 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -0,0 +1,228 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq}; +use clippy_utils::{meets_msrv, msrvs}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::ExprKind::Assign; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::sym; + +const ACCEPTABLE_METHODS: [&[&str]; 4] = [ + &paths::HASHSET_ITER, + &paths::BTREESET_ITER, + &paths::SLICE_INTO, + &paths::VEC_DEQUE_ITER, +]; +const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 6] = [ + (sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)), + (sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)), + (sym::HashSet, Some(msrvs::HASH_SET_RETAIN)), + (sym::HashMap, Some(msrvs::HASH_MAP_RETAIN)), + (sym::Vec, None), + (sym::VecDeque, None), +]; + +declare_clippy_lint! { + /// ### What it does + /// Checks for code to be replaced by `.retain()`. + /// ### Why is this bad? + /// `.retain()` is simpler and avoids needless allocation. + /// ### Example + /// ```rust + /// let mut vec = vec![0, 1, 2]; + /// vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); + /// vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); + /// ``` + /// Use instead: + /// ```rust + /// let mut vec = vec![0, 1, 2]; + /// vec.retain(|x| x % 2 == 0); + /// ``` + #[clippy::version = "1.63.0"] + pub MANUAL_RETAIN, + perf, + "`retain()` is simpler and the same functionalitys" +} + +pub struct ManualRetain { + msrv: Option<RustcVersion>, +} + +impl ManualRetain { + #[must_use] + pub fn new(msrv: Option<RustcVersion>) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]); + +impl<'tcx> LateLintPass<'tcx> for ManualRetain { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let Assign(left_expr, collect_expr, _) = &parent_expr.kind + && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind + && seg.args.is_none() + && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind + && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) + && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) { + check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv); + check_iter(cx, parent_expr, left_expr, target_expr, self.msrv); + check_to_owned(cx, parent_expr, left_expr, target_expr, self.msrv); + } + } + + extract_msrv_attr!(LateContext); +} + +fn check_into_iter( + cx: &LateContext<'_>, + parent_expr: &hir::Expr<'_>, + left_expr: &hir::Expr<'_>, + target_expr: &hir::Expr<'_>, + msrv: Option<RustcVersion>, +) { + if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind + && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) + && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) + && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind + && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) + && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER) + && match_acceptable_type(cx, left_expr, msrv) + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + suggest(cx, parent_expr, left_expr, target_expr); + } +} + +fn check_iter( + cx: &LateContext<'_>, + parent_expr: &hir::Expr<'_>, + left_expr: &hir::Expr<'_>, + target_expr: &hir::Expr<'_>, + msrv: Option<RustcVersion>, +) { + if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind + && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) + && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED) + || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED)) + && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind + && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) + && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) + && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind + && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) + && match_acceptable_def_path(cx, iter_expr_def_id) + && match_acceptable_type(cx, left_expr, msrv) + && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) { + suggest(cx, parent_expr, left_expr, filter_expr); + } +} + +fn check_to_owned( + cx: &LateContext<'_>, + parent_expr: &hir::Expr<'_>, + left_expr: &hir::Expr<'_>, + target_expr: &hir::Expr<'_>, + msrv: Option<RustcVersion>, +) { + if meets_msrv(msrv, msrvs::STRING_RETAIN) + && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind + && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) + && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) + && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind + && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) + && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) + && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind + && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id) + && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) + && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() + && is_type_diagnostic_item(cx, ty, sym::String) + && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) { + suggest(cx, parent_expr, left_expr, filter_expr); + } +} + +fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) { + if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind + && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind + && let filter_body = cx.tcx.hir().body(body) + && let [filter_params] = filter_body.params + && let Some(sugg) = match filter_params.pat.kind { + hir::PatKind::Binding(_, _, filter_param_ident, None) => { + Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, ".."))) + }, + hir::PatKind::Tuple([key_pat, value_pat], _) => { + make_sugg(cx, key_pat, value_pat, left_expr, filter_body) + }, + hir::PatKind::Ref(pat, _) => { + match pat.kind { + hir::PatKind::Binding(_, _, filter_param_ident, None) => { + Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, ".."))) + }, + _ => None + } + }, + _ => None + } { + span_lint_and_sugg( + cx, + MANUAL_RETAIN, + parent_expr.span, + "this expression can be written more simply using `.retain()`", + "consider calling `.retain()` instead", + sugg, + Applicability::MachineApplicable + ); + } +} + +fn make_sugg( + cx: &LateContext<'_>, + key_pat: &rustc_hir::Pat<'_>, + value_pat: &rustc_hir::Pat<'_>, + left_expr: &hir::Expr<'_>, + filter_body: &hir::Body<'_>, +) -> Option<String> { + match (&key_pat.kind, &value_pat.kind) { + (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Binding(_, _, value_param_ident, None)) => { + Some(format!( + "{}.retain(|{}, &mut {}| {})", + snippet(cx, left_expr.span, ".."), + key_param_ident, + value_param_ident, + snippet(cx, filter_body.value.span, "..") + )) + }, + (hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Wild) => Some(format!( + "{}.retain(|{}, _| {})", + snippet(cx, left_expr.span, ".."), + key_param_ident, + snippet(cx, filter_body.value.span, "..") + )), + (hir::PatKind::Wild, hir::PatKind::Binding(_, _, value_param_ident, None)) => Some(format!( + "{}.retain(|_, &mut {}| {})", + snippet(cx, left_expr.span, ".."), + value_param_ident, + snippet(cx, filter_body.value.span, "..") + )), + _ => None, + } +} + +fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> bool { + ACCEPTABLE_METHODS + .iter() + .any(|&method| match_def_path(cx, collect_def_id, method)) +} + +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Option<RustcVersion>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); + ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| { + is_type_diagnostic_item(cx, expr_ty, *ty) + && acceptable_msrv.map_or(true, |acceptable_msrv| meets_msrv(msrv, acceptable_msrv)) + }) +} diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 3533de54a1e3d..95c312f1fe26b 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if method.ident.name == sym::map; let ty = cx.typeck_results().expr_ty(&args[0]); if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator); - if let hir::ExprKind::Closure { body, .. } = args[1].kind; + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind; then { let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(&closure_body.value); diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs index 0c22144104872..21d0e19eb0a48 100644 --- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs +++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind}; +use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -119,12 +119,12 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { if method.ident.as_str() == "map_err" && args.len() == 2 { // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span // fields - if let ExprKind::Closure { + if let ExprKind::Closure(&Closure { capture_clause, body, fn_decl_span, .. - } = args[1].kind + }) = args[1].kind { // check if this is by Reference (meaning there's no move statement) if capture_clause == CaptureBy::Ref { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 663246b4c8622..af9d948af00e6 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -169,7 +169,7 @@ fn unit_closure<'tcx>( expr: &hir::Expr<'_>, ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> { if_chain! { - if let hir::ExprKind::Closure { fn_decl, body, .. } = expr.kind; + if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind; let body = cx.tcx.hir().body(body); let body_expr = &body.value; if fn_decl.inputs.len() == 1; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 16fefea552019..15513de7d860d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -285,7 +285,7 @@ impl<'a> NormalizedPat<'a> { // TODO: Handle negative integers. They're currently treated as a wild match. ExprKind::Lit(lit) => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), - LitKind::ByteStr(ref bytes) => Self::LitBytes(&**bytes), + LitKind::ByteStr(ref bytes) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val), 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 9df2db45dcf83..5ae4a65acaf33 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 @@ -55,7 +55,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e cx, (ex, expr), (bind_names, matched_vars), - &*snippet_body, + &snippet_body, &mut applicability, Some(span), ); @@ -88,7 +88,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e cx, (ex, expr), (bind_names, matched_vars), - &*snippet_body, + &snippet_body, &mut applicability, None, ); diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 8302ce426e570..fa3b8d1fceaac 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -118,7 +118,7 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad MATCH_STR_CASE_MISMATCH, bad_case_span, "this `match` arm has a differing case than its expression", - &*format!("consider changing the case of this arm to respect `{}`", method_str), + &format!("consider changing the case of this arm to respect `{}`", method_str), format!("\"{}\"", suggestion), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 3e765173fb9f3..3077b999f4ee4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -791,7 +791,7 @@ declare_clippy_lint! { /// the match block and thus will not unlock. /// /// ### Example - /// ```rust.ignore + /// ```rust,ignore /// # use std::sync::Mutex; /// /// # struct State {} @@ -963,7 +963,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { - significant_drop_in_scrutinee::check(cx, expr, ex, source); + significant_drop_in_scrutinee::check(cx, expr, ex, arms, source); } collapsible_match::check_match(cx, arms); @@ -1041,7 +1041,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { - self.infallible_destructuring_match_linted |= infallible_destructuring_match::check(cx, local); + self.infallible_destructuring_match_linted |= + local.els.is_none() && infallible_destructuring_match::check(cx, local); } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { 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 0ea3f3b673b7d..8499e050af242 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 @@ -3,16 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::needs_ordered_drop; -use clippy_utils::{higher, match_def_path}; -use clippy_utils::{is_lang_ctor, is_trait_method, paths}; +use clippy_utils::visitors::any_temporaries_need_ordered_drop; +use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, PollPending}; -use rustc_hir::{ - intravisit::{walk_expr, Visitor}, - Arm, Block, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp, -}; +use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; use rustc_span::sym; @@ -47,79 +44,6 @@ fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> { } } -// Checks if there are any temporaries created in the given expression for which drop order -// matters. -fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - struct V<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - res: bool, - } - impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - match expr.kind { - // Taking the reference of a value leaves a temporary - // e.g. In `&String::new()` the string is a temporary value. - // Remaining fields are temporary values - // e.g. In `(String::new(), 0).1` the string is a temporary value. - ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => { - if !matches!(expr.kind, ExprKind::Path(_)) { - if needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) { - self.res = true; - } else { - self.visit_expr(expr); - } - } - }, - // the base type is always taken by reference. - // e.g. In `(vec![0])[0]` the vector is a temporary value. - ExprKind::Index(base, index) => { - if !matches!(base.kind, ExprKind::Path(_)) { - if needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) { - self.res = true; - } else { - self.visit_expr(base); - } - } - self.visit_expr(index); - }, - // Method calls can take self by reference. - // e.g. In `String::new().len()` the string is a temporary value. - ExprKind::MethodCall(_, [self_arg, args @ ..], _) => { - if !matches!(self_arg.kind, ExprKind::Path(_)) { - let self_by_ref = self - .cx - .typeck_results() - .type_dependent_def_id(expr.hir_id) - .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref()); - if self_by_ref && needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg)) { - self.res = true; - } else { - self.visit_expr(self_arg); - } - } - args.iter().for_each(|arg| self.visit_expr(arg)); - }, - // Either explicitly drops values, or changes control flow. - ExprKind::DropTemps(_) - | ExprKind::Ret(_) - | ExprKind::Break(..) - | ExprKind::Yield(..) - | ExprKind::Block(Block { expr: None, .. }, _) - | ExprKind::Loop(..) => (), - - // Only consider the final expression. - ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr), - - _ => walk_expr(self, expr), - } - } - } - - let mut v = V { cx, res: false }; - v.visit_expr(expr); - v.res -} - fn find_sugg_for_if_let<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, @@ -191,7 +115,7 @@ fn find_sugg_for_if_let<'tcx>( // scrutinee would be, so they have to be considered as well. // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held // for the duration if body. - let needs_drop = needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr); + let needs_drop = needs_ordered_drop(cx, check_ty) || any_temporaries_need_ordered_drop(cx, let_expr); // check that `while_let_on_iterator` lint does not trigger if_chain! { @@ -362,9 +286,9 @@ fn find_good_method_for_match<'a>( .qpath_res(path_right, arms[1].pat.hir_id) .opt_def_id()?; let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) { - (&(*arms[0].body).kind, &(*arms[1].body).kind) + (&arms[0].body.kind, &arms[1].body.kind) } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) { - (&(*arms[1].body).kind, &(*arms[0].body).kind) + (&arms[1].body.kind, &arms[0].body.kind) } else { return None; }; 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 dcaf6f865de36..0704a5af52595 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 @@ -1,10 +1,10 @@ use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_attr; use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::{get_attr, is_lint_allowed}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Expr, ExprKind, MatchSource}; +use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{Ty, TypeAndMut}; @@ -16,12 +16,23 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, scrutinee: &'tcx Expr<'_>, + arms: &'tcx [Arm<'_>], source: MatchSource, ) { + if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) { + return; + } + if let Some((suggestions, message)) = has_significant_drop_in_scrutinee(cx, scrutinee, source) { for found in suggestions { span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| { set_diagnostic(diag, cx, expr, found); + let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None); + diag.span_label(s, "temporary lives until here"); + for span in has_significant_drop_in_arms(cx, arms) { + diag.span_label(span, "another value with significant `Drop` created here"); + } + diag.note("this might lead to deadlocks or other unexpected behavior"); }); } } @@ -80,22 +91,77 @@ fn has_significant_drop_in_scrutinee<'tcx, 'a>( let mut helper = SigDropHelper::new(cx); helper.find_sig_drop(scrutinee).map(|drops| { let message = if source == MatchSource::Normal { - "temporary with significant drop in match scrutinee" + "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression" } else { - "temporary with significant drop in for loop" + "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression" }; (drops, message) }) } +struct SigDropChecker<'a, 'tcx> { + seen_types: FxHashSet<Ty<'tcx>>, + cx: &'a LateContext<'tcx>, +} + +impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { + fn new(cx: &'a LateContext<'tcx>) -> SigDropChecker<'a, 'tcx> { + SigDropChecker { + seen_types: FxHashSet::default(), + cx, + } + } + + fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> { + self.cx.typeck_results().expr_ty(ex) + } + + fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool { + !self.seen_types.insert(ty) + } + + fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + if let Some(adt) = ty.ty_adt_def() { + if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 { + return true; + } + } + + match ty.kind() { + rustc_middle::ty::Adt(a, b) => { + for f in a.all_fields() { + let ty = f.ty(cx.tcx, b); + if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) { + return true; + } + } + + for generic_arg in b.iter() { + if let GenericArgKind::Type(ty) = generic_arg.unpack() { + if self.has_sig_drop_attr(cx, ty) { + return true; + } + } + } + false + }, + rustc_middle::ty::Array(ty, _) + | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) + | rustc_middle::ty::Ref(_, ty, _) + | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty), + _ => false, + } + } +} + struct SigDropHelper<'a, 'tcx> { cx: &'a LateContext<'tcx>, is_chain_end: bool, - seen_types: FxHashSet<Ty<'tcx>>, has_significant_drop: bool, current_sig_drop: Option<FoundSigDrop>, sig_drop_spans: Option<Vec<FoundSigDrop>>, special_handling_for_binary_op: bool, + sig_drop_checker: SigDropChecker<'a, 'tcx>, } #[expect(clippy::enum_variant_names)] @@ -118,11 +184,11 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { SigDropHelper { cx, is_chain_end: true, - seen_types: FxHashSet::default(), has_significant_drop: false, current_sig_drop: None, sig_drop_spans: None, special_handling_for_binary_op: false, + sig_drop_checker: SigDropChecker::new(cx), } } @@ -163,7 +229,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { if self.current_sig_drop.is_some() { return; } - let ty = self.get_type(expr); + let ty = self.sig_drop_checker.get_type(expr); if ty.is_ref() { // We checked that the type was ref, so builtin_deref will return Some TypeAndMut, // but let's avoid any chance of an ICE @@ -187,14 +253,6 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { } } - fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> { - self.cx.typeck_results().expr_ty(ex) - } - - fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool { - !self.seen_types.insert(ty) - } - fn visit_exprs_for_binary_ops( &mut self, left: &'tcx Expr<'_>, @@ -214,44 +272,15 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { self.special_handling_for_binary_op = false; } - - fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - if let Some(adt) = ty.ty_adt_def() { - if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 { - return true; - } - } - - match ty.kind() { - rustc_middle::ty::Adt(a, b) => { - for f in a.all_fields() { - let ty = f.ty(cx.tcx, b); - if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) { - return true; - } - } - - for generic_arg in b.iter() { - if let GenericArgKind::Type(ty) = generic_arg.unpack() { - if self.has_sig_drop_attr(cx, ty) { - return true; - } - } - } - false - }, - rustc_middle::ty::Array(ty, _) - | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) - | rustc_middle::ty::Ref(_, ty, _) - | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty), - _ => false, - } - } } impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { - if !self.is_chain_end && self.has_sig_drop_attr(self.cx, self.get_type(ex)) { + if !self.is_chain_end + && self + .sig_drop_checker + .has_sig_drop_attr(self.cx, self.sig_drop_checker.get_type(ex)) + { self.has_significant_drop = true; return; } @@ -330,3 +359,38 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { } } } + +struct ArmSigDropHelper<'a, 'tcx> { + sig_drop_checker: SigDropChecker<'a, 'tcx>, + found_sig_drop_spans: FxHashSet<Span>, +} + +impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> { + fn new(cx: &'a LateContext<'tcx>) -> ArmSigDropHelper<'a, 'tcx> { + ArmSigDropHelper { + sig_drop_checker: SigDropChecker::new(cx), + found_sig_drop_spans: FxHashSet::<Span>::default(), + } + } +} + +fn has_significant_drop_in_arms<'tcx, 'a>(cx: &'a LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> { + let mut helper = ArmSigDropHelper::new(cx); + for arm in arms { + helper.visit_expr(arm.body); + } + helper.found_sig_drop_spans +} + +impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if self + .sig_drop_checker + .has_sig_drop_attr(self.sig_drop_checker.cx, self.sig_drop_checker.get_type(ex)) + { + self.found_sig_drop_spans.insert(ex.span); + return; + } + walk_expr(self, ex); + } +} 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 0c4cb45d147ca..92091a0c3395f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -140,70 +140,45 @@ fn check_opt_like<'a>( ty: Ty<'a>, els: Option<&Expr<'_>>, ) { - // list of candidate `Enum`s we know will never get any more members - let candidates = &[ - (&paths::COW, "Borrowed"), - (&paths::COW, "Cow::Borrowed"), - (&paths::COW, "Cow::Owned"), - (&paths::COW, "Owned"), - (&paths::OPTION, "None"), - (&paths::RESULT, "Err"), - (&paths::RESULT, "Ok"), - ]; - - // We want to suggest to exclude an arm that contains only wildcards or forms the exhaustive - // match with the second branch, without enum variants in matches. - if !contains_only_wilds(arms[1].pat) && !form_exhaustive_matches(arms[0].pat, arms[1].pat) { - return; + // We don't want to lint if the second arm contains an enum which could + // have more variants in the future. + if form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat) { + report_single_pattern(cx, ex, arms, expr, els); } +} +/// Returns `true` if all of the types in the pattern are enums which we know +/// won't be expanded in the future +fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) -> bool { let mut paths_and_types = Vec::new(); - if !collect_pat_paths(&mut paths_and_types, cx, arms[1].pat, ty) { - return; - } + collect_pat_paths(&mut paths_and_types, cx, pat, ty); + paths_and_types.iter().all(|ty| in_candidate_enum(cx, *ty)) +} - let in_candidate_enum = |path_info: &(String, Ty<'_>)| -> bool { - let (path, ty) = path_info; - for &(ty_path, pat_path) in candidates { - if path == pat_path && match_type(cx, *ty, ty_path) { - return true; - } +/// Returns `true` if the given type is an enum we know won't be expanded in the future +fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool { + // list of candidate `Enum`s we know will never get any more members + let candidates = [&paths::COW, &paths::OPTION, &paths::RESULT]; + + for candidate_ty in candidates { + if match_type(cx, ty, candidate_ty) { + return true; } - false - }; - if paths_and_types.iter().all(in_candidate_enum) { - report_single_pattern(cx, ex, arms, expr, els); } + false } -/// Collects paths and their types from the given patterns. Returns true if the given pattern could -/// be simplified, false otherwise. -fn collect_pat_paths<'a>(acc: &mut Vec<(String, Ty<'a>)>, cx: &LateContext<'a>, pat: &Pat<'_>, ty: Ty<'a>) -> bool { +/// Collects types from the given pattern +fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<'_>, ty: Ty<'a>) { match pat.kind { - PatKind::Wild => true, - PatKind::Tuple(inner, _) => inner.iter().all(|p| { + PatKind::Tuple(inner, _) => inner.iter().for_each(|p| { let p_ty = cx.typeck_results().pat_ty(p); - collect_pat_paths(acc, cx, p, p_ty) + collect_pat_paths(acc, cx, p, p_ty); }), - PatKind::TupleStruct(ref path, ..) => { - let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_qpath(path, false); - }); - acc.push((path, ty)); - true - }, - PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => { - acc.push((ident.to_string(), ty)); - true + PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => { + acc.push(ty); }, - PatKind::Path(ref path) => { - let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_qpath(path, false); - }); - acc.push((path, ty)); - true - }, - _ => false, + _ => {}, } } @@ -218,7 +193,7 @@ fn contains_only_wilds(pat: &Pat<'_>) -> bool { /// Returns true if the given patterns forms only exhaustive matches that don't contain enum /// patterns without a wildcard. -fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool { +fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, right: &Pat<'_>) -> bool { match (&left.kind, &right.kind) { (PatKind::Wild, _) | (_, PatKind::Wild) => true, (PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => { @@ -264,6 +239,10 @@ fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool { } true }, + (PatKind::TupleStruct(..), PatKind::Path(_)) => pat_in_candidate_enum(cx, ty, right), + (PatKind::TupleStruct(..), PatKind::TupleStruct(_, inner, _)) => { + pat_in_candidate_enum(cx, ty, right) && inner.iter().all(contains_only_wilds) + }, _ => false, } } 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 d31b736982b34..2f117e4dcc374 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 @@ -150,7 +150,7 @@ pub(crate) trait BindInsteadOfMap { } match arg.kind { - hir::ExprKind::Closure { body, fn_decl_span, .. } => { + hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => { let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(&closure_body.value); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 58c3e52e138c4..7dbfd95c50db4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; +use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp}; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol}; @@ -22,8 +22,8 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy hir::ExprKind::Path(QPath::Resolved(_, segments)) => { segments.segments.last().unwrap().ident.name == method_name }, - hir::ExprKind::Closure { body, .. } => { - let body = cx.tcx.hir().body(*body); + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(&body.value); let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { @@ -106,7 +106,7 @@ pub(super) fn check<'tcx>( if is_trait_method(cx, map_recv, sym::Iterator); // filter(|x| ...is_some())... - if let ExprKind::Closure { body: filter_body_id, .. } = filter_arg.kind; + if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind; let filter_body = cx.tcx.hir().body(filter_body_id); if let [filter_param] = filter_body.params; // optional ref pattern: `filter(|&x| ..)` @@ -129,7 +129,7 @@ pub(super) fn check<'tcx>( if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" }; // ...map(|x| ...unwrap()) - if let ExprKind::Closure { body: map_body_id, .. } = map_arg.kind; + if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind; let map_body = cx.tcx.hir().body(map_body_id); if let [map_param] = map_body.params; if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs index f5410c7fd7fc8..43e9451f7d37e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr |diag| { if_chain! { if let Some(id) = path_to_local(recv); - if let Node::Binding(pat) = cx.tcx.hir().get(id); + if let Node::Pat(pat) = cx.tcx.hir().get(id); if let PatKind::Binding(ann, _, _, _) = pat.kind; if ann != BindingAnnotation::Mutable; then { diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs index f447940ea3b5a..13853dec99de8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_sugg_for_edges; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; @@ -14,17 +14,17 @@ use super::MAP_FLATTEN; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) { if let Some((caller_ty_name, method_to_use)) = try_get_caller_ty_name_and_method_name(cx, expr, recv, map_arg) { let mut applicability = Applicability::MachineApplicable; - let help_msgs = [ - &format!("try replacing `map` with `{}`", method_to_use), - "and remove the `.flatten()`", - ]; + let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability); - span_lint_and_sugg_for_edges( + span_lint_and_sugg( cx, MAP_FLATTEN, expr.span.with_lo(map_span.lo()), &format!("called `map(..).flatten()` on `{}`", caller_ty_name), - &help_msgs, + &format!( + "try replacing `map` with `{}` and remove the `.flatten()`", + method_to_use + ), format!("{}({})", method_to_use, closure_snippet), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 912499bf96b94..20cad0f181e95 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( .map_or(false, |fun_def_id| { deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) }), - hir::ExprKind::Closure { body, .. } => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(&closure_body.value); diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs index 2d71bd6f240fc..5a39b82b027d1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs @@ -71,7 +71,7 @@ pub(super) fn check<'tcx>( if is_option { let self_snippet = snippet(cx, recv.span, ".."); if_chain! { - if let hir::ExprKind::Closure { body, fn_decl_span, .. } = map_arg.kind; + if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind; let arg_snippet = snippet(cx, fn_decl_span, ".."); let body = cx.tcx.hir().body(body); if let Some((func, [arg_char])) = reduce_unit_expression(&body.value); 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 448dc4e6147ff..3d1208824fa34 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 @@ -4,7 +4,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_mac use clippy_utils::ty::{implements_trait, match_type}; use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths}; use if_chain::if_chain; -use rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -33,7 +32,6 @@ pub(super) fn check<'tcx>( arg: &hir::Expr<'_>, or_has_args: bool, span: Span, - method_span: Span, ) -> bool { let is_default_default = || is_trait_item(cx, fun, sym::Default); @@ -56,19 +54,14 @@ pub(super) fn check<'tcx>( then { let mut applicability = Applicability::MachineApplicable; let hint = "unwrap_or_default()"; - let mut sugg_span = span; + let sugg_span = span; - let mut sugg: String = format!( + let sugg: String = format!( "{}.{}", snippet_with_applicability(cx, self_expr.span, "..", &mut applicability), hint ); - if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES { - sugg_span = method_span.with_hi(span.hi()); - sugg = hint.to_string(); - } - span_lint_and_sugg( cx, OR_FUN_CALL, @@ -178,7 +171,7 @@ pub(super) fn check<'tcx>( match inner_arg.kind { hir::ExprKind::Call(fun, or_args) => { let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span, method_span) { + if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span); } diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index b11f4531a912c..7572ba3fe9a94 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -41,7 +41,7 @@ pub(super) fn check<'tcx>( let mut applicability = Applicability::MachineApplicable; let any_search_snippet = if_chain! { if search_method == "find"; - if let hir::ExprKind::Closure { body, .. } = search_arg.kind; + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind; let closure_body = cx.tcx.hir().body(body); if let Some(closure_arg) = closure_body.params.get(0); then { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index a405467f5e8af..bafa6fc584d48 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< return; } - if let hir::ExprKind::Closure { body, .. } = arg.kind { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { let body = cx.tcx.hir().body(body); let arg_id = body.params[0].pat.hir_id; let mutates_arg = diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index 913c4dbedc301..c3531d4d0511e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -29,7 +29,7 @@ pub(super) fn check( ) { if_chain! { // Extract the body of the closure passed to fold - if let hir::ExprKind::Closure { body, .. } = acc.kind; + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(&closure_body.value); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 865f6d0318eb9..21767d74c87b8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); if is_option || is_result { - if let hir::ExprKind::Closure { body, .. } = arg.kind { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind { let body = cx.tcx.hir().body(body); let body_expr = &body.value; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index b4c6bfb31ed1c..b3276f1394ed2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -427,5 +427,5 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D /// Returns true if the named method is `ToString::to_string`. fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name.as_str() == "to_string" && is_diag_trait_item(cx, method_def_id, sym::ToString) + method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString) } diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 01bf871198a5c..be7df08d89f05 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -1,28 +1,21 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; +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::ty::{implements_trait, is_copy}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, - StmtKind, TyKind, UnOp, + StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; -use rustc_span::symbol::sym; -use clippy_utils::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; -use clippy_utils::{ - get_item_name, get_parent_expr, in_constant, is_integer_const, iter_input_pats, last_path_segment, - match_any_def_paths, path_def_id, paths, unsext, SpanlessEq, -}; +use clippy_utils::{get_parent_expr, in_constant, iter_input_pats, last_path_segment, SpanlessEq}; declare_clippy_lint! { /// ### What it does @@ -58,122 +51,6 @@ declare_clippy_lint! { style, "an entire binding declared as `ref`, in a function argument or a `let` statement" } - -declare_clippy_lint! { - /// ### What it does - /// Checks for comparisons to NaN. - /// - /// ### Why is this bad? - /// NaN does not compare meaningfully to anything – not - /// even itself – so those comparisons are simply wrong. - /// - /// ### Example - /// ```rust - /// # let x = 1.0; - /// if x == f32::NAN { } - /// ``` - /// - /// Use instead: - /// ```rust - /// # let x = 1.0f32; - /// if x.is_nan() { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub CMP_NAN, - correctness, - "comparisons to `NAN`, which will always return false, probably not intended" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for (in-)equality comparisons on floating-point - /// values (apart from zero), except in functions called `*eq*` (which probably - /// implement equality for a type involving floats). - /// - /// ### Why is this bad? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). - /// - /// ### Example - /// ```rust - /// let x = 1.2331f64; - /// let y = 1.2332f64; - /// - /// if y == 1.23f64 { } - /// if y != x {} // where both are floats - /// ``` - /// - /// Use instead: - /// ```rust - /// # let x = 1.2331f64; - /// # let y = 1.2332f64; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (y - 1.23f64).abs() < error_margin { } - /// if (y - x).abs() > error_margin { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FLOAT_CMP, - pedantic, - "using `==` or `!=` on float values instead of comparing difference with an epsilon" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for conversions to owned values just for the sake - /// of a comparison. - /// - /// ### Why is this bad? - /// The comparison can operate on a reference, so creating - /// an owned value effectively throws it away directly afterwards, which is - /// needlessly consuming code and heap space. - /// - /// ### Example - /// ```rust - /// # let x = "foo"; - /// # let y = String::from("foo"); - /// if x.to_owned() == y {} - /// ``` - /// - /// Use instead: - /// ```rust - /// # let x = "foo"; - /// # let y = String::from("foo"); - /// if x == y {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub CMP_OWNED, - perf, - "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for getting the remainder of a division by one or minus - /// one. - /// - /// ### Why is this bad? - /// The result for a divisor of one can only ever be zero; for - /// minus one it can cause panic/overflow (if the left operand is the minimal value of - /// the respective integer type) or results in zero. No one will write such code - /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that - /// contest, it's probably a bad idea. Use something more underhanded. - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// let a = x % 1; - /// let a = x % -1; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MODULO_ONE, - correctness, - "taking a number modulo +/-1, which can either panic/overflow or always returns 0" -} - declare_clippy_lint! { /// ### What it does /// Checks for the use of bindings with a single leading @@ -244,51 +121,11 @@ declare_clippy_lint! { "using `0 as *{const, mut} T`" } -declare_clippy_lint! { - /// ### What it does - /// Checks for (in-)equality comparisons on floating-point - /// value and constant, except in functions called `*eq*` (which probably - /// implement equality for a type involving floats). - /// - /// ### Why is this bad? - /// Floating point calculations are usually imprecise, so - /// asking if two values are *exactly* equal is asking for trouble. For a good - /// guide on what to do, see [the floating point - /// guide](http://www.floating-point-gui.de/errors/comparison). - /// - /// ### Example - /// ```rust - /// let x: f64 = 1.0; - /// const ONE: f64 = 1.00; - /// - /// if x == ONE { } // where both are floats - /// ``` - /// - /// Use instead: - /// ```rust - /// # let x: f64 = 1.0; - /// # const ONE: f64 = 1.00; - /// let error_margin = f64::EPSILON; // Use an epsilon for comparison - /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. - /// // let error_margin = std::f64::EPSILON; - /// if (x - ONE).abs() < error_margin { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FLOAT_CMP_CONST, - restriction, - "using `==` or `!=` on float constants instead of comparing difference with an epsilon" -} - declare_lint_pass!(MiscLints => [ TOPLEVEL_REF_ARG, - CMP_NAN, - FLOAT_CMP, - CMP_OWNED, - MODULO_ONE, USED_UNDERSCORE_BINDING, SHORT_CIRCUIT_STATEMENT, ZERO_PTR, - FLOAT_CMP_CONST ]); impl<'tcx> LateLintPass<'tcx> for MiscLints { @@ -398,16 +235,9 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - match expr.kind { - ExprKind::Cast(e, ty) => { - check_cast(cx, expr.span, e, ty); - return; - }, - ExprKind::Binary(ref cmp, left, right) => { - check_binary(cx, expr, cmp, left, right); - return; - }, - _ => {}, + if let ExprKind::Cast(e, ty) = expr.kind { + check_cast(cx, expr.span, e, ty); + return; } if in_attributes_expansion(expr) || expr.span.is_desugaring(DesugaringKind::Await) { // Don't lint things expanded by #[derive(...)], etc or `await` desugaring @@ -455,236 +285,6 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } } -fn get_lint_and_message( - is_comparing_constants: bool, - is_comparing_arrays: bool, -) -> (&'static rustc_lint::Lint, &'static str) { - if is_comparing_constants { - ( - FLOAT_CMP_CONST, - if is_comparing_arrays { - "strict comparison of `f32` or `f64` constant arrays" - } else { - "strict comparison of `f32` or `f64` constant" - }, - ) - } else { - ( - FLOAT_CMP, - if is_comparing_arrays { - "strict comparison of `f32` or `f64` arrays" - } else { - "strict comparison of `f32` or `f64`" - }, - ) - } -} - -fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) { - if_chain! { - if !in_constant(cx, cmp_expr.hir_id); - if let Some((value, _)) = constant(cx, cx.typeck_results(), expr); - if match value { - Constant::F32(num) => num.is_nan(), - Constant::F64(num) => num.is_nan(), - _ => false, - }; - then { - span_lint( - cx, - CMP_NAN, - cmp_expr.span, - "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead", - ); - } - } -} - -fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { - res - } else { - false - } -} - -fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - match constant(cx, cx.typeck_results(), expr) { - Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f { - Constant::F32(f) => *f == 0.0 || (*f).is_infinite(), - Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), - _ => false, - }), - _ => false, - } -} - -// Return true if `expr` is the result of `signum()` invoked on a float value. -fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - // The negation of a signum is still a signum - if let ExprKind::Unary(UnOp::Neg, child_expr) = expr.kind { - return is_signum(cx, child_expr); - } - - if_chain! { - if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind; - if sym!(signum) == method_name.ident.name; - // Check that the receiver of the signum() is a float (expressions[0] is the receiver of - // the method call) - then { - return is_float(cx, self_arg); - } - } - false -} - -fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let value = &cx.typeck_results().expr_ty(expr).peel_refs().kind(); - - if let ty::Array(arr_ty, _) = value { - return matches!(arr_ty.kind(), ty::Float(_)); - }; - - matches!(value, ty::Float(_)) -} - -fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) -} - -#[expect(clippy::too_many_lines)] -fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { - #[derive(Default)] - struct EqImpl { - ty_eq_other: bool, - other_eq_ty: bool, - } - - impl EqImpl { - fn is_implemented(&self) -> bool { - self.ty_eq_other || self.other_eq_ty - } - } - - fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> { - cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl { - ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]), - other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]), - }) - } - - let typeck = cx.typeck_results(); - let (arg, arg_span) = match expr.kind { - ExprKind::MethodCall(.., [arg], _) - if typeck - .type_dependent_def_id(expr.hir_id) - .and_then(|id| cx.tcx.trait_of_item(id)) - .map_or(false, |id| { - matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned)) - }) => - { - (arg, arg.span) - }, - ExprKind::Call(path, [arg]) - if path_def_id(cx, path) - .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM])) - .map_or(false, |idx| match idx { - 0 => true, - 1 => !is_copy(cx, typeck.expr_ty(expr)), - _ => false, - }) => - { - (arg, arg.span) - }, - _ => return, - }; - - let arg_ty = typeck.expr_ty(arg); - let other_ty = typeck.expr_ty(other); - - let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); - let with_deref = arg_ty - .builtin_deref(true) - .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) - .unwrap_or_default(); - - if !with_deref.is_implemented() && !without_deref.is_implemented() { - return; - } - - let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::Deref, _)); - - let lint_span = if other_gets_derefed { - expr.span.to(other.span) - } else { - expr.span - }; - - span_lint_and_then( - cx, - CMP_OWNED, - lint_span, - "this creates an owned instance just for comparison", - |diag| { - // This also catches `PartialEq` implementations that call `to_owned`. - if other_gets_derefed { - diag.span_label(lint_span, "try implementing the comparison without allocating"); - return; - } - - let arg_snip = snippet(cx, arg_span, ".."); - let expr_snip; - let eq_impl; - if with_deref.is_implemented() { - expr_snip = format!("*{}", arg_snip); - eq_impl = with_deref; - } else { - expr_snip = arg_snip.to_string(); - eq_impl = without_deref; - }; - - let span; - let hint; - if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { - span = expr.span; - hint = expr_snip; - } else { - span = expr.span.to(other.span); - - let cmp_span = if other.span < expr.span { - other.span.between(expr.span) - } else { - expr.span.between(other.span) - }; - if eq_impl.ty_eq_other { - hint = format!( - "{}{}{}", - expr_snip, - snippet(cx, cmp_span, ".."), - snippet(cx, other.span, "..") - ); - } else { - hint = format!( - "{}{}{}", - snippet(cx, other.span, ".."), - snippet(cx, cmp_span, ".."), - expr_snip - ); - } - } - - diag.span_suggestion( - span, - "try", - hint, - Applicability::MachineApplicable, // snippet - ); - }, - ); -} - /// Heuristic to see if an expression is used. Should be compatible with /// `unused_variables`'s idea /// of what it means for an expression to be "used". @@ -701,7 +301,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::MacroKind; if expr.span.from_expansion() { let data = expr.span.ctxt().outer_expn_data(); - matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _)) + matches!(data.kind, ExpnKind::Macro(MacroKind::Attr|MacroKind::Derive, _)) } else { false } @@ -740,74 +340,3 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) } } } - -fn check_binary<'a>( - cx: &LateContext<'a>, - expr: &Expr<'_>, - cmp: &rustc_span::source_map::Spanned<rustc_hir::BinOpKind>, - left: &'a Expr<'_>, - right: &'a Expr<'_>, -) { - let op = cmp.node; - if op.is_comparison() { - check_nan(cx, left, expr); - check_nan(cx, right, expr); - check_to_owned(cx, left, right, true); - check_to_owned(cx, right, left, false); - } - if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } - - // Allow comparing the results of signum() - if is_signum(cx, left) && is_signum(cx, right) { - return; - } - - if let Some(name) = get_item_name(cx, expr) { - let name = name.as_str(); - if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { - return; - } - } - let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); - span_lint_and_then(cx, lint, expr.span, msg, |diag| { - let lhs = Sugg::hir(cx, left, ".."); - let rhs = Sugg::hir(cx, right, ".."); - - if !is_comparing_arrays { - diag.span_suggestion( - expr.span, - "consider comparing them within some margin of error", - format!( - "({}).abs() {} error_margin", - lhs - rhs, - if op == BinOpKind::Eq { '<' } else { '>' } - ), - Applicability::HasPlaceholders, // snippet - ); - } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); - }); - } else if op == BinOpKind::Rem { - if is_integer_const(cx, right, 1) { - span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); - } - - if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { - if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { - span_lint( - cx, - MODULO_ONE, - expr.span, - "any number modulo -1 will panic/overflow or result in 0", - ); - } - }; - } -} diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 7e2531c7ca5f0..4db103bbc1305 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::trait_ref_of_method; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::TypeVisitable; use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs deleted file mode 100644 index 623d22bc9bdfe..0000000000000 --- a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs +++ /dev/null @@ -1,85 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using - /// a lazy and. - /// - /// ### Why is this bad? - /// The bitwise operators do not support short-circuiting, so it may hinder code performance. - /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` - /// - /// ### Known problems - /// This lint evaluates only when the right side is determined to have no side effects. At this time, that - /// determination is quite conservative. - /// - /// ### Example - /// ```rust - /// let (x,y) = (true, false); - /// if x & !y {} // where both x and y are booleans - /// ``` - /// Use instead: - /// ```rust - /// let (x,y) = (true, false); - /// if x && !y {} - /// ``` - #[clippy::version = "1.54.0"] - pub NEEDLESS_BITWISE_BOOL, - pedantic, - "Boolean expressions that use bitwise rather than lazy operators" -} - -declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]); - -fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); - if_chain! { - if !expr.span.from_expansion(); - if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind()); - if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr; - if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind; - if !right.can_have_side_effects(); - then { - return true; - } - } - false -} - -fn suggestion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { - if let ExprKind::Binary(ref op, left, right) = expr.kind { - if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) { - let op_snippet = match op.node { - BinOpKind::BitAnd => "&&", - _ => "||", - }; - return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet)); - } - } - None -} - -impl LateLintPass<'_> for NeedlessBitwiseBool { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if is_bitwise_operation(cx, expr) { - span_lint_and_then( - cx, - NEEDLESS_BITWISE_BOOL, - expr.span, - "use of bitwise operator instead of lazy operator between booleans", - |diag| { - if let Some(sugg) = suggestion_snippet(cx, expr) { - diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable); - } - }, - ); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 48ac695f2acfb..10e188ecb79a6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -1,7 +1,7 @@ use rustc_errors::Applicability; use rustc_hir::{ intravisit::{walk_expr, Visitor}, - Expr, ExprKind, Stmt, StmtKind, + Closure, Expr, ExprKind, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some(); // Skip the lint if the body is not block because this is simpler than `for` loop. // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. - if let ExprKind::Closure { body, .. } = for_each_arg.kind; + if let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind; let body = cx.tcx.hir().body(body); if let ExprKind::Block(..) = body.value.kind; then { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 8b273aca7d020..0cbef1c95fe95 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -13,7 +13,7 @@ use rustc_hir::{HirIdMap, HirIdSet}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, TypeFoldable}; +use rustc_middle::ty::{self, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index ce6bb38b7c0e9..b087cfb36b116 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -1,7 +1,9 @@ use clippy_utils::consts::{self, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::has_enclosing_paren; use if_chain::if_chain; +use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -58,7 +60,12 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { then { let mut applicability = Applicability::MachineApplicable; - let suggestion = format!("-{}", snippet_with_applicability(cx, exp.span, "..", &mut applicability)); + let snip = snippet_with_applicability(cx, exp.span, "..", &mut applicability); + let suggestion = if exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { + format!("-({})", snip) + } else { + format!("-{}", snip) + }; span_lint_and_sugg( cx, NEG_MULTIPLY, diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 6598413c77ecc..819646bb6780e 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -92,6 +92,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { if_chain! { if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id); if let Some(init) = local.init; + if local.els.is_none(); if !local.pat.span.from_expansion(); if has_no_effect(cx, init); if let PatKind::Binding(_, _, ident, _) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 1727275a4e06a..6bce5fbd4c1fe 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -6,6 +6,7 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::in_constant; +use clippy_utils::macros::macro_backtrace; use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -18,7 +19,7 @@ use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{InnerSpan, Span, DUMMY_SP}; +use rustc_span::{sym, InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; // FIXME: this is a correctness problem but there's no suitable @@ -147,7 +148,7 @@ fn is_value_unfrozen_raw<'tcx>( match val.ty().kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let val = cx.tcx.destructure_mir_constant(cx.param_env, val); val.fields.iter().any(|field| inner(cx, *field)) @@ -250,8 +251,14 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { if let ItemKind::Const(hir_ty, body_id) = it.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - - if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + if !macro_backtrace(it.span).last().map_or(false, |macro_call| { + matches!( + cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::thread_local_macro) + ) + }) && is_unfrozen(cx, ty) + && is_value_unfrozen_poly(cx, body_id, ty) + { lint(cx, Source::Item { item: it.span }); } } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 7f6b535c7b16c..b96af06b8d7c6 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -159,12 +159,10 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { #[must_use] fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> { - for &list in ALLOWED_TO_BE_SIMILAR { - if allowed_to_be_similar(interned_name, list) { - return Some(list); - } - } - None + ALLOWED_TO_BE_SIMILAR + .iter() + .find(|&&list| allowed_to_be_similar(interned_name, list)) + .copied() } #[must_use] @@ -328,7 +326,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { // add the pattern after the expression because the bindings aren't available // yet in the init // expression - SimilarNamesNameVisitor(self).visit_pat(&*local.pat); + SimilarNamesNameVisitor(self).visit_pat(&local.pat); } fn visit_block(&mut self, blk: &'tcx Block) { self.single_char_names.push(vec![]); diff --git a/src/tools/clippy/clippy_lints/src/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/numeric_arithmetic.rs deleted file mode 100644 index 5c4de3381496c..0000000000000 --- a/src/tools/clippy/clippy_lints/src/numeric_arithmetic.rs +++ /dev/null @@ -1,170 +0,0 @@ -use clippy_utils::consts::constant_simple; -use clippy_utils::diagnostics::span_lint; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; - -declare_clippy_lint! { - /// ### What it does - /// Checks for integer arithmetic operations which could overflow or panic. - /// - /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable - /// of overflowing according to the [Rust - /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is - /// attempted. - /// - /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. - /// - /// ### Example - /// ```rust - /// # let a = 0; - /// a + 1; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INTEGER_ARITHMETIC, - restriction, - "any integer arithmetic expression which could overflow or panic" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for float arithmetic. - /// - /// ### Why is this bad? - /// For some embedded systems or kernel development, it - /// can be useful to rule out floating-point numbers. - /// - /// ### Example - /// ```rust - /// # let a = 0.0; - /// a + 1.0; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FLOAT_ARITHMETIC, - restriction, - "any floating-point arithmetic statement" -} - -#[derive(Copy, Clone, Default)] -pub struct NumericArithmetic { - expr_span: Option<Span>, - /// This field is used to check whether expressions are constants, such as in enum discriminants - /// and consts - const_span: Option<Span>, -} - -impl_lint_pass!(NumericArithmetic => [INTEGER_ARITHMETIC, FLOAT_ARITHMETIC]); - -impl<'tcx> LateLintPass<'tcx> for NumericArithmetic { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if self.expr_span.is_some() { - return; - } - - if let Some(span) = self.const_span { - if span.contains(expr.span) { - return; - } - } - match &expr.kind { - hir::ExprKind::Binary(op, l, r) | hir::ExprKind::AssignOp(op, l, r) => { - match op.node { - hir::BinOpKind::And - | hir::BinOpKind::Or - | hir::BinOpKind::BitAnd - | hir::BinOpKind::BitOr - | hir::BinOpKind::BitXor - | hir::BinOpKind::Eq - | hir::BinOpKind::Lt - | hir::BinOpKind::Le - | hir::BinOpKind::Ne - | hir::BinOpKind::Ge - | hir::BinOpKind::Gt => return, - _ => (), - } - - let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); - if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { - match op.node { - hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { - hir::ExprKind::Lit(_lit) => (), - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if let hir::ExprKind::Lit(lit) = &expr.kind { - if let rustc_ast::ast::LitKind::Int(1, _) = lit.node { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_span = Some(expr.span); - } - } - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_span = Some(expr.span); - }, - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_span = Some(expr.span); - }, - } - } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { - span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); - self.expr_span = Some(expr.span); - } - }, - hir::ExprKind::Unary(hir::UnOp::Neg, arg) => { - let ty = cx.typeck_results().expr_ty(arg); - if constant_simple(cx, cx.typeck_results(), expr).is_none() { - if ty.is_integral() { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_span = Some(expr.span); - } else if ty.is_floating_point() { - span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); - self.expr_span = Some(expr.span); - } - } - }, - _ => (), - } - } - - fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if Some(expr.span) == self.expr_span { - self.expr_span = None; - } - } - - fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner_def_id(body.id()); - - match cx.tcx.hir().body_owner_kind(body_owner) { - hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => { - let body_span = cx.tcx.def_span(body_owner); - - if let Some(span) = self.const_span { - if span.contains(body_span) { - return; - } - } - self.const_span = Some(body_span); - }, - hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (), - } - } - - fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner(body.id()); - let body_span = cx.tcx.hir().span(body_owner); - - if let Some(span) = self.const_span { - if span.contains(body_span) { - return; - } - } - self.const_span = None; - } -} diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 677ac998b5682..d461668077e0a 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor}; use rustc_hir::{ - Arm, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment, + Arm, Closure, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; @@ -298,7 +298,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> { }, ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms), // since analysing the closure is not easy, just set all variables in it to side-effect - ExprKind::Closure { body, .. } => { + ExprKind::Closure(&Closure { body, .. }) => { let body = self.tcx.hir().body(body); self.visit_body(body); let vars = std::mem::take(&mut self.ret_vars); diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs similarity index 53% rename from src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs rename to src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs index 7665aa8380b3c..1ec4240afefe5 100644 --- a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -1,7 +1,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use clippy_utils::comparisons::{normalize_comparison, Rel}; use clippy_utils::consts::{constant, Constant}; @@ -10,73 +9,41 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_isize_or_usize; use clippy_utils::{clip, int_bits, unsext}; -declare_clippy_lint! { - /// ### What it does - /// Checks for comparisons where one side of the relation is - /// either the minimum or maximum value for its type and warns if it involves a - /// case that is always true or always false. Only integer and boolean types are - /// checked. - /// - /// ### Why is this bad? - /// An expression like `min <= x` may misleadingly imply - /// that it is possible for `x` to be less than the minimum. Expressions like - /// `max < x` are probably mistakes. - /// - /// ### Known problems - /// For `usize` the size of the current compile target will - /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such - /// a comparison to detect target pointer width will trigger this lint. One can - /// use `mem::sizeof` and compare its value or conditional compilation - /// attributes - /// like `#[cfg(target_pointer_width = "64")] ..` instead. - /// - /// ### Example - /// ```rust - /// let vec: Vec<isize> = Vec::new(); - /// if vec.len() <= 0 {} - /// if 100 > i32::MAX {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub ABSURD_EXTREME_COMPARISONS, - correctness, - "a comparison with a maximum or minimum value that is always true or false" -} +use super::ABSURD_EXTREME_COMPARISONS; -declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]); - -impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind { - if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { - if !expr.span.from_expansion() { - let msg = "this comparison involving the minimum or maximum element for this \ - type contains a case that is always true or always false"; - - let conclusion = match result { - AbsurdComparisonResult::AlwaysFalse => "this comparison is always false".to_owned(), - AbsurdComparisonResult::AlwaysTrue => "this comparison is always true".to_owned(), - AbsurdComparisonResult::InequalityImpossible => format!( - "the case where the two sides are not equal never occurs, consider using `{} == {}` \ - instead", - snippet(cx, lhs.span, "lhs"), - snippet(cx, rhs.span, "rhs") - ), - }; - - let help = format!( - "because `{}` is the {} value for this type, {}", - snippet(cx, culprit.expr.span, "x"), - match culprit.which { - ExtremeType::Minimum => "minimum", - ExtremeType::Maximum => "maximum", - }, - conclusion - ); - - span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); - } - } - } +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + lhs: &'tcx Expr<'_>, + rhs: &'tcx Expr<'_>, +) { + if let Some((culprit, result)) = detect_absurd_comparison(cx, op, lhs, rhs) { + let msg = "this comparison involving the minimum or maximum element for this \ + type contains a case that is always true or always false"; + + let conclusion = match result { + AbsurdComparisonResult::AlwaysFalse => "this comparison is always false".to_owned(), + AbsurdComparisonResult::AlwaysTrue => "this comparison is always true".to_owned(), + AbsurdComparisonResult::InequalityImpossible => format!( + "the case where the two sides are not equal never occurs, consider using `{} == {}` \ + instead", + snippet(cx, lhs.span, "lhs"), + snippet(cx, rhs.span, "rhs") + ), + }; + + let help = format!( + "because `{}` is the {} value for this type, {}", + snippet(cx, culprit.expr.span, "x"), + match culprit.which { + ExtremeType::Minimum => "minimum", + ExtremeType::Maximum => "maximum", + }, + conclusion + ); + + span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); } } diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs new file mode 100644 index 0000000000000..979e0a66707dd --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -0,0 +1,101 @@ +use clippy_utils::binop_traits; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; +use clippy_utils::{eq_expr_value, trait_ref_of_method}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_lint::LateContext; + +use super::ASSIGN_OP_PATTERN; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + assignee: &'tcx hir::Expr<'_>, + e: &'tcx hir::Expr<'_>, +) { + if let hir::ExprKind::Binary(op, l, r) = &e.kind { + let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { + let ty = cx.typeck_results().expr_ty(assignee); + let rty = cx.typeck_results().expr_ty(rhs); + if_chain! { + if let Some((_, lang_item)) = binop_traits(op.node); + if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item); + let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id); + if trait_ref_of_method(cx, parent_fn) + .map_or(true, |t| t.path.res.def_id() != trait_id); + if implements_trait(cx, ty, trait_id, &[rty.into()]); + then { + span_lint_and_then( + cx, + ASSIGN_OP_PATTERN, + expr.span, + "manual implementation of an assign operation", + |diag| { + if let (Some(snip_a), Some(snip_r)) = + (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) + { + diag.span_suggestion( + expr.span, + "replace it with", + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r), + Applicability::MachineApplicable, + ); + } + }, + ); + } + } + }; + + let mut visitor = ExprVisitor { + assignee, + counter: 0, + cx, + }; + + walk_expr(&mut visitor, e); + + if visitor.counter == 1 { + // a = a op b + if eq_expr_value(cx, assignee, l) { + lint(assignee, r); + } + // a = b commutative_op a + // Limited to primitive type as these ops are know to be commutative + if eq_expr_value(cx, assignee, r) && cx.typeck_results().expr_ty(assignee).is_primitive_ty() { + match op.node { + hir::BinOpKind::Add + | hir::BinOpKind::Mul + | hir::BinOpKind::And + | hir::BinOpKind::Or + | hir::BinOpKind::BitXor + | hir::BinOpKind::BitAnd + | hir::BinOpKind::BitOr => { + lint(assignee, l); + }, + _ => {}, + } + } + } + } +} + +struct ExprVisitor<'a, 'tcx> { + assignee: &'a hir::Expr<'a>, + counter: u8, + cx: &'a LateContext<'tcx>, +} + +impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + if eq_expr_value(self.cx, self.assignee, expr) { + self.counter += 1; + } + + walk_expr(self, expr); + } +} diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs similarity index 51% rename from src/tools/clippy/clippy_lints/src/bit_mask.rs rename to src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index dc7e400fdc281..74387fbc87be0 100644 --- a/src/tools/clippy/clippy_lints/src/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -1,161 +1,23 @@ use clippy_utils::consts::{constant, Constant}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::sugg::Sugg; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; +use clippy_utils::diagnostics::span_lint; use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_lint::LateContext; use rustc_span::source_map::Span; -declare_clippy_lint! { - /// ### What it does - /// Checks for incompatible bit masks in comparisons. - /// - /// The formula for detecting if an expression of the type `_ <bit_op> m - /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of - /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following - /// table: - /// - /// |Comparison |Bit Op|Example |is always|Formula | - /// |------------|------|-------------|---------|----------------------| - /// |`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | - /// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | - /// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | - /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` | - /// |`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` | - /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` | - /// - /// ### Why is this bad? - /// If the bits that the comparison cares about are always - /// set to zero or one by the bit mask, the comparison is constant `true` or - /// `false` (depending on mask, compared value, and operators). - /// - /// So the code is actively misleading, and the only reason someone would write - /// this intentionally is to win an underhanded Rust contest or create a - /// test-case for this lint. - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// if (x & 1 == 2) { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub BAD_BIT_MASK, - correctness, - "expressions of the form `_ & mask == select` that will only ever return `true` or `false`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for bit masks in comparisons which can be removed - /// without changing the outcome. The basic structure can be seen in the - /// following table: - /// - /// |Comparison| Bit Op |Example |equals | - /// |----------|----------|------------|-------| - /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`| - /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`| - /// - /// ### Why is this bad? - /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask), - /// but still a bit misleading, because the bit mask is ineffective. - /// - /// ### Known problems - /// False negatives: This lint will only match instances - /// where we have figured out the math (which is for a power-of-two compared - /// value). This means things like `x | 1 >= 7` (which would be better written - /// as `x >= 6`) will not be reported (but bit masks like this are fairly - /// uncommon). - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// if (x | 1 > 3) { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INEFFECTIVE_BIT_MASK, - correctness, - "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for bit masks that can be replaced by a call - /// to `trailing_zeros` - /// - /// ### Why is this bad? - /// `x.trailing_zeros() > 4` is much clearer than `x & 15 - /// == 0` - /// - /// ### Known problems - /// llvm generates better code for `x & 15 == 0` on x86 - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// if x & 0b1111 == 0 { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub VERBOSE_BIT_MASK, - pedantic, - "expressions where a bit mask is less readable than the corresponding method call" -} +use super::{BAD_BIT_MASK, INEFFECTIVE_BIT_MASK}; -#[derive(Copy, Clone)] -pub struct BitMask { - verbose_bit_mask_threshold: u64, -} - -impl BitMask { - #[must_use] - pub fn new(verbose_bit_mask_threshold: u64) -> Self { - Self { - verbose_bit_mask_threshold, - } - } -} - -impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]); - -impl<'tcx> LateLintPass<'tcx> for BitMask { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Binary(cmp, left, right) = &e.kind { - if cmp.node.is_comparison() { - if let Some(cmp_opt) = fetch_int_literal(cx, right) { - check_compare(cx, left, cmp.node, cmp_opt, e.span); - } else if let Some(cmp_val) = fetch_int_literal(cx, left) { - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span); - } - } - } - - if let ExprKind::Binary(op, left, right) = &e.kind - && BinOpKind::Eq == op.node - && let ExprKind::Binary(op1, left1, right1) = &left.kind - && BinOpKind::BitAnd == op1.node - && let ExprKind::Lit(lit) = &right1.kind - && let LitKind::Int(n, _) = lit.node - && let ExprKind::Lit(lit1) = &right.kind - && let LitKind::Int(0, _) = lit1.node - && n.leading_zeros() == n.count_zeros() - && n > u128::from(self.verbose_bit_mask_threshold) - { - span_lint_and_then( - cx, - VERBOSE_BIT_MASK, - e.span, - "bit mask could be simplified with a call to `trailing_zeros`", - |diag| { - let sugg = Sugg::hir(cx, left1, "...").maybe_par(); - diag.span_suggestion( - e.span, - "try", - format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()), - Applicability::MaybeIncorrect, - ); - }, - ); +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + if op.is_comparison() { + if let Some(cmp_opt) = fetch_int_literal(cx, right) { + check_compare(cx, left, op, cmp_opt, e.span); + } else if let Some(cmp_val) = fetch_int_literal(cx, left) { + check_compare(cx, right, invert_cmp(op), cmp_val, e.span); } } } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs new file mode 100644 index 0000000000000..786ae1552ad3d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs @@ -0,0 +1,30 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::in_constant; +use rustc_hir::{BinOpKind, Expr}; +use rustc_lint::LateContext; + +use super::CMP_NAN; + +pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &Expr<'_>) { + if op.is_comparison() && !in_constant(cx, e.hir_id) && (is_nan(cx, lhs) || is_nan(cx, rhs)) { + span_lint( + cx, + CMP_NAN, + e.span, + "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead", + ); + } +} + +fn is_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + if let Some((value, _)) = constant(cx, cx.typeck_results(), e) { + match value { + Constant::F32(num) => num.is_nan(), + Constant::F64(num) => num.is_nan(), + _ => false, + } + } else { + false + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs new file mode 100644 index 0000000000000..e1f9b5906f667 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -0,0 +1,147 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, is_copy}; +use clippy_utils::{match_any_def_paths, path_def_id, paths}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; +use rustc_span::symbol::sym; + +use super::CMP_OWNED; + +pub(super) fn check(cx: &LateContext<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &Expr<'_>) { + if op.is_comparison() { + check_op(cx, lhs, rhs, true); + check_op(cx, rhs, lhs, false); + } +} + +#[derive(Default)] +struct EqImpl { + ty_eq_other: bool, + other_eq_ty: bool, +} +impl EqImpl { + fn is_implemented(&self) -> bool { + self.ty_eq_other || self.other_eq_ty + } +} + +fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> { + cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl { + ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]), + other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]), + }) +} + +fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { + let typeck = cx.typeck_results(); + let (arg, arg_span) = match expr.kind { + ExprKind::MethodCall(.., [arg], _) + if typeck + .type_dependent_def_id(expr.hir_id) + .and_then(|id| cx.tcx.trait_of_item(id)) + .map_or(false, |id| { + matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned)) + }) => + { + (arg, arg.span) + }, + ExprKind::Call(path, [arg]) + if path_def_id(cx, path) + .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM])) + .map_or(false, |idx| match idx { + 0 => true, + 1 => !is_copy(cx, typeck.expr_ty(expr)), + _ => false, + }) => + { + (arg, arg.span) + }, + _ => return, + }; + + let arg_ty = typeck.expr_ty(arg); + let other_ty = typeck.expr_ty(other); + + let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); + let with_deref = arg_ty + .builtin_deref(true) + .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) + .unwrap_or_default(); + + if !with_deref.is_implemented() && !without_deref.is_implemented() { + return; + } + + let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::Deref, _)); + + let lint_span = if other_gets_derefed { + expr.span.to(other.span) + } else { + expr.span + }; + + span_lint_and_then( + cx, + CMP_OWNED, + lint_span, + "this creates an owned instance just for comparison", + |diag| { + // This also catches `PartialEq` implementations that call `to_owned`. + if other_gets_derefed { + diag.span_label(lint_span, "try implementing the comparison without allocating"); + return; + } + + let arg_snip = snippet(cx, arg_span, ".."); + let expr_snip; + let eq_impl; + if with_deref.is_implemented() { + expr_snip = format!("*{}", arg_snip); + eq_impl = with_deref; + } else { + expr_snip = arg_snip.to_string(); + eq_impl = without_deref; + }; + + let span; + let hint; + if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { + span = expr.span; + hint = expr_snip; + } else { + span = expr.span.to(other.span); + + let cmp_span = if other.span < expr.span { + other.span.between(expr.span) + } else { + expr.span.between(other.span) + }; + if eq_impl.ty_eq_other { + hint = format!( + "{}{}{}", + expr_snip, + snippet(cx, cmp_span, ".."), + snippet(cx, other.span, "..") + ); + } else { + hint = format!( + "{}{}{}", + snippet(cx, other.span, ".."), + snippet(cx, cmp_span, ".."), + expr_snip + ); + } + } + + diag.span_suggestion( + span, + "try", + hint, + Applicability::MachineApplicable, // snippet + ); + }, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs new file mode 100644 index 0000000000000..56a86d0ffa212 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs @@ -0,0 +1,54 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eq_expr_value; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::DOUBLE_COMPARISONS; + +#[expect(clippy::similar_names)] +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, span: Span) { + let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) { + (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => { + (lb.node, llhs, lrhs, rb.node, rlhs, rrhs) + }, + _ => return, + }; + if !(eq_expr_value(cx, llhs, rlhs) && eq_expr_value(cx, lrhs, rrhs)) { + return; + } + macro_rules! lint_double_comparison { + ($op:tt) => {{ + let mut applicability = Applicability::MachineApplicable; + let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability); + let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability); + let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str); + span_lint_and_sugg( + cx, + DOUBLE_COMPARISONS, + span, + "this binary expression can be simplified", + "try", + sugg, + applicability, + ); + }}; + } + match (op, lkind, rkind) { + (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => { + lint_double_comparison!(<=); + }, + (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => { + lint_double_comparison!(>=); + }, + (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => { + lint_double_comparison!(!=); + }, + (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => { + lint_double_comparison!(==); + }, + _ => (), + }; +} diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs new file mode 100644 index 0000000000000..0d067d1e1968c --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs @@ -0,0 +1,44 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::DURATION_SUBSEC; + +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + if op == BinOpKind::Div + && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) + && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) + { + let suggested_fn = match (method_path.ident.as_str(), divisor) { + ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", + ("subsec_nanos", 1_000) => "subsec_micros", + _ => return, + }; + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + DURATION_SUBSEC, + expr.span, + &format!("calling `{}()` is more concise than this calculation", suggested_fn), + "try", + format!( + "{}.{}()", + snippet_with_applicability(cx, self_arg.span, "_", &mut applicability), + suggested_fn + ), + applicability, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs new file mode 100644 index 0000000000000..44cf0bb06120a --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; +use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; +use rustc_hir::{BinOpKind, Expr}; +use rustc_lint::LateContext; + +use super::EQ_OP; + +pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let Some((macro_call, macro_name)) + = first_node_macro_backtrace(cx, e).find_map(|macro_call| { + let name = cx.tcx.item_name(macro_call.def_id); + matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne") + .then(|| (macro_call, name)) + }) + && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) + && eq_expr_value(cx, lhs, rhs) + && macro_call.is_local() + && !is_in_test_function(cx.tcx, e.hir_id) + { + span_lint( + cx, + EQ_OP, + lhs.span.to(rhs.span), + &format!("identical args used in this `{}!` macro call", macro_name), + ); + } +} + +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { + span_lint( + cx, + EQ_OP, + e.span, + &format!("equal expressions as operands to `{}`", op.as_str()), + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs new file mode 100644 index 0000000000000..066e08f3bd4ca --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/erasing_op.rs @@ -0,0 +1,53 @@ +use clippy_utils::consts::{constant_simple, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::same_type_and_consts; + +use rustc_hir::{BinOpKind, Expr}; +use rustc_lint::LateContext; +use rustc_middle::ty::TypeckResults; + +use super::ERASING_OP; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + let tck = cx.typeck_results(); + match op { + BinOpKind::Mul | BinOpKind::BitAnd => { + check_op(cx, tck, left, right, e); + check_op(cx, tck, right, left, e); + }, + BinOpKind::Div => check_op(cx, tck, left, right, e), + _ => (), + } +} + +fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool { + let input_ty = tck.expr_ty(input).peel_refs(); + let output_ty = tck.expr_ty(output).peel_refs(); + !same_type_and_consts(input_ty, output_ty) +} + +fn check_op<'tcx>( + cx: &LateContext<'tcx>, + tck: &TypeckResults<'tcx>, + op: &Expr<'tcx>, + other: &Expr<'tcx>, + parent: &Expr<'tcx>, +) { + if constant_simple(cx, tck, op) == Some(Constant::Int(0)) { + if different_types(tck, other, parent) { + return; + } + span_lint( + cx, + ERASING_OP, + parent.span, + "this operation will always return zero. This is likely not the intended outcome", + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs new file mode 100644 index 0000000000000..0ef793443ff45 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -0,0 +1,139 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::get_item_name; +use clippy_utils::sugg::Sugg; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +use super::{FLOAT_CMP, FLOAT_CMP_CONST}; + +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { + if is_allowed(cx, left) || is_allowed(cx, right) { + return; + } + + // Allow comparing the results of signum() + if is_signum(cx, left) && is_signum(cx, right) { + return; + } + + if let Some(name) = get_item_name(cx, expr) { + let name = name.as_str(); + if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { + return; + } + } + let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); + let (lint, msg) = get_lint_and_message( + is_named_constant(cx, left) || is_named_constant(cx, right), + is_comparing_arrays, + ); + span_lint_and_then(cx, lint, expr.span, msg, |diag| { + let lhs = Sugg::hir(cx, left, ".."); + let rhs = Sugg::hir(cx, right, ".."); + + if !is_comparing_arrays { + diag.span_suggestion( + expr.span, + "consider comparing them within some margin of error", + format!( + "({}).abs() {} error_margin", + lhs - rhs, + if op == BinOpKind::Eq { '<' } else { '>' } + ), + Applicability::HasPlaceholders, // snippet + ); + } + diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); + }); + } +} + +fn get_lint_and_message( + is_comparing_constants: bool, + is_comparing_arrays: bool, +) -> (&'static rustc_lint::Lint, &'static str) { + if is_comparing_constants { + ( + FLOAT_CMP_CONST, + if is_comparing_arrays { + "strict comparison of `f32` or `f64` constant arrays" + } else { + "strict comparison of `f32` or `f64` constant" + }, + ) + } else { + ( + FLOAT_CMP, + if is_comparing_arrays { + "strict comparison of `f32` or `f64` arrays" + } else { + "strict comparison of `f32` or `f64`" + }, + ) + } +} + +fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { + res + } else { + false + } +} + +fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + match constant(cx, cx.typeck_results(), expr) { + Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), + Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), + Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f { + Constant::F32(f) => *f == 0.0 || (*f).is_infinite(), + Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), + _ => false, + }), + _ => false, + } +} + +// Return true if `expr` is the result of `signum()` invoked on a float value. +fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + // The negation of a signum is still a signum + if let ExprKind::Unary(UnOp::Neg, child_expr) = expr.kind { + return is_signum(cx, child_expr); + } + + if_chain! { + if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind; + if sym!(signum) == method_name.ident.name; + // Check that the receiver of the signum() is a float (expressions[0] is the receiver of + // the method call) + then { + return is_float(cx, self_arg); + } + } + false +} + +fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let value = &cx.typeck_results().expr_ty(expr).peel_refs().kind(); + + if let ty::Array(arr_ty, _) = value { + return matches!(arr_ty.kind(), ty::Float(_)); + }; + + matches!(value, ty::Float(_)) +} + +fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) +} diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs new file mode 100644 index 0000000000000..a0a8b6aabd9e3 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs @@ -0,0 +1,71 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{match_def_path, paths, sugg}; +use if_chain::if_chain; +use rustc_ast::util::parser::AssocOp; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::source_map::Spanned; + +use super::FLOAT_EQUALITY_WITHOUT_ABS; + +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + lhs: &'tcx Expr<'_>, + rhs: &'tcx Expr<'_>, +) { + let (lhs, rhs) = match op { + BinOpKind::Lt => (lhs, rhs), + BinOpKind::Gt => (rhs, lhs), + _ => return, + }; + + if_chain! { + // left hand side is a subtraction + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Sub, + .. + }, + val_l, + val_r, + ) = lhs.kind; + + // right hand side matches either f32::EPSILON or f64::EPSILON + if let ExprKind::Path(ref epsilon_path) = rhs.kind; + if let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id); + if match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON); + + // values of the subtractions on the left hand side are of the type float + let t_val_l = cx.typeck_results().expr_ty(val_l); + let t_val_r = cx.typeck_results().expr_ty(val_r); + if let ty::Float(_) = t_val_l.kind(); + if let ty::Float(_) = t_val_r.kind(); + + then { + let sug_l = sugg::Sugg::hir(cx, val_l, ".."); + let sug_r = sugg::Sugg::hir(cx, val_r, ".."); + // format the suggestion + let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()); + // spans the lint + span_lint_and_then( + cx, + FLOAT_EQUALITY_WITHOUT_ABS, + expr.span, + "float equality check without `.abs()`", + | diag | { + diag.span_suggestion( + lhs.span, + "add `.abs()`", + suggestion, + Applicability::MaybeIncorrect, + ); + } + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs similarity index 60% rename from src/tools/clippy/clippy_lints/src/identity_op.rs rename to src/tools/clippy/clippy_lints/src/operators/identity_op.rs index 419ea5a6811b8..b48d6c4e2e2af 100644 --- a/src/tools/clippy/clippy_lints/src/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs @@ -3,61 +3,40 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{clip, unsext}; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, Node}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::{BinOpKind, Expr, ExprKind, Node}; +use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -declare_clippy_lint! { - /// ### What it does - /// Checks for identity operations, e.g., `x + 0`. - /// - /// ### Why is this bad? - /// This code can be removed without changing the - /// meaning. So it just obscures what's going on. Delete it mercilessly. - /// - /// ### Example - /// ```rust - /// # let x = 1; - /// x / 1 + 0 * 1 - 0 | 0; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub IDENTITY_OP, - complexity, - "using identity operations, e.g., `x + 0` or `y / 1`" -} - -declare_lint_pass!(IdentityOp => [IDENTITY_OP]); +use super::IDENTITY_OP; -impl<'tcx> LateLintPass<'tcx> for IdentityOp { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - if let ExprKind::Binary(cmp, left, right) = &expr.kind { - if !is_allowed(cx, *cmp, left, right) { - match cmp.node { - BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { - check(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right)); - check(cx, right, 0, expr.span, left.span, Parens::Unneeded); - }, - BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => { - check(cx, right, 0, expr.span, left.span, Parens::Unneeded); - }, - BinOpKind::Mul => { - check(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right)); - check(cx, right, 1, expr.span, left.span, Parens::Unneeded); - }, - BinOpKind::Div => check(cx, right, 1, expr.span, left.span, Parens::Unneeded), - BinOpKind::BitAnd => { - check(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right)); - check(cx, right, -1, expr.span, left.span, Parens::Unneeded); - }, - BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span), - _ => (), - } - } +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + if !is_allowed(cx, op, left, right) { + match op { + BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { + check_op(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right)); + check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded); + }, + BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => { + check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded); + }, + BinOpKind::Mul => { + check_op(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right)); + check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded); + }, + BinOpKind::Div => check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded), + BinOpKind::BitAnd => { + check_op(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right)); + check_op(cx, right, -1, expr.span, left.span, Parens::Unneeded); + }, + BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span), + _ => (), } } } @@ -108,12 +87,12 @@ fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) Parens::Needed } -fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool { +fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> bool { // This lint applies to integers !cx.typeck_results().expr_ty(left).peel_refs().is_integral() || !cx.typeck_results().expr_ty(right).peel_refs().is_integral() // `1 << 0` is a common pattern in bit manipulation code - || (cmp.node == BinOpKind::Shl + || (cmp == BinOpKind::Shl && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0)) && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))) } @@ -130,7 +109,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span } } -fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens) { +fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) { let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs new file mode 100644 index 0000000000000..631d10f4a72e9 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs @@ -0,0 +1,27 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::INTEGER_DIVISION; + +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + op: hir::BinOpKind, + left: &'tcx hir::Expr<'_>, + right: &'tcx hir::Expr<'_>, +) { + if op == hir::BinOpKind::Div + && cx.typeck_results().expr_ty(left).is_integral() + && cx.typeck_results().expr_ty(right).is_integral() + { + span_lint_and_help( + cx, + INTEGER_DIVISION, + expr.span, + "integer division", + None, + "division of integers may cause loss of precision. consider using floats", + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs new file mode 100644 index 0000000000000..0024384d9278d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -0,0 +1,84 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::eq_expr_value; +use clippy_utils::source::snippet_opt; +use clippy_utils::sugg; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::MISREFACTORED_ASSIGN_OP; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + op: hir::BinOpKind, + lhs: &'tcx hir::Expr<'_>, + rhs: &'tcx hir::Expr<'_>, +) { + if let hir::ExprKind::Binary(binop, l, r) = &rhs.kind { + if op != binop.node { + return; + } + // lhs op= l op r + if eq_expr_value(cx, lhs, l) { + lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, r); + } + // lhs op= l commutative_op r + if is_commutative(op) && eq_expr_value(cx, lhs, r) { + lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, l); + } + } +} + +fn lint_misrefactored_assign_op( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + op: hir::BinOpKind, + rhs: &hir::Expr<'_>, + assignee: &hir::Expr<'_>, + rhs_other: &hir::Expr<'_>, +) { + span_lint_and_then( + cx, + MISREFACTORED_ASSIGN_OP, + expr.span, + "variable appears on both sides of an assignment operation", + |diag| { + if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { + let a = &sugg::Sugg::hir(cx, assignee, ".."); + let r = &sugg::Sugg::hir(cx, rhs, ".."); + let long = format!("{} = {}", snip_a, sugg::make_binop(op.into(), a, r)); + diag.span_suggestion( + expr.span, + &format!( + "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with", + snip_a, + snip_a, + op.as_str(), + snip_r, + long + ), + format!("{} {}= {}", snip_a, op.as_str(), snip_r), + Applicability::MaybeIncorrect, + ); + diag.span_suggestion( + expr.span, + "or", + long, + Applicability::MaybeIncorrect, // snippet + ); + } + }, + ); +} + +#[must_use] +fn is_commutative(op: hir::BinOpKind) -> bool { + use rustc_hir::BinOpKind::{ + Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub, + }; + match op { + Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true, + Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs new file mode 100644 index 0000000000000..35fe405bcf14f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -0,0 +1,849 @@ +use rustc_hir::{Body, Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +mod absurd_extreme_comparisons; +mod assign_op_pattern; +mod bit_mask; +mod cmp_nan; +mod cmp_owned; +mod double_comparison; +mod duration_subsec; +mod eq_op; +mod erasing_op; +mod float_cmp; +mod float_equality_without_abs; +mod identity_op; +mod integer_division; +mod misrefactored_assign_op; +mod modulo_arithmetic; +mod modulo_one; +mod needless_bitwise_bool; +mod numeric_arithmetic; +mod op_ref; +mod ptr_eq; +mod self_assignment; +mod verbose_bit_mask; + +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons where one side of the relation is + /// either the minimum or maximum value for its type and warns if it involves a + /// case that is always true or always false. Only integer and boolean types are + /// checked. + /// + /// ### Why is this bad? + /// An expression like `min <= x` may misleadingly imply + /// that it is possible for `x` to be less than the minimum. Expressions like + /// `max < x` are probably mistakes. + /// + /// ### Known problems + /// For `usize` the size of the current compile target will + /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such + /// a comparison to detect target pointer width will trigger this lint. One can + /// use `mem::sizeof` and compare its value or conditional compilation + /// attributes + /// like `#[cfg(target_pointer_width = "64")] ..` instead. + /// + /// ### Example + /// ```rust + /// let vec: Vec<isize> = Vec::new(); + /// if vec.len() <= 0 {} + /// if 100 > i32::MAX {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub ABSURD_EXTREME_COMPARISONS, + correctness, + "a comparison with a maximum or minimum value that is always true or false" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for integer arithmetic operations which could overflow or panic. + /// + /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable + /// of overflowing according to the [Rust + /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), + /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is + /// attempted. + /// + /// ### Why is this bad? + /// Integer overflow will trigger a panic in debug builds or will wrap in + /// release mode. Division by zero will cause a panic in either mode. In some applications one + /// wants explicitly checked, wrapping or saturating arithmetic. + /// + /// ### Example + /// ```rust + /// # let a = 0; + /// a + 1; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub INTEGER_ARITHMETIC, + restriction, + "any integer arithmetic expression which could overflow or panic" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for float arithmetic. + /// + /// ### Why is this bad? + /// For some embedded systems or kernel development, it + /// can be useful to rule out floating-point numbers. + /// + /// ### Example + /// ```rust + /// # let a = 0.0; + /// a + 1.0; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub FLOAT_ARITHMETIC, + restriction, + "any floating-point arithmetic statement" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `a = a op b` or `a = b commutative_op a` + /// patterns. + /// + /// ### Why is this bad? + /// These can be written as the shorter `a op= b`. + /// + /// ### Known problems + /// While forbidden by the spec, `OpAssign` traits may have + /// implementations that differ from the regular `Op` impl. + /// + /// ### Example + /// ```rust + /// let mut a = 5; + /// let b = 0; + /// // ... + /// + /// a = a + b; + /// ``` + /// + /// Use instead: + /// ```rust + /// let mut a = 5; + /// let b = 0; + /// // ... + /// + /// a += b; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub ASSIGN_OP_PATTERN, + style, + "assigning the result of an operation on a variable to that same variable" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `a op= a op b` or `a op= b op a` patterns. + /// + /// ### Why is this bad? + /// Most likely these are bugs where one meant to write `a + /// op= b`. + /// + /// ### Known problems + /// Clippy cannot know for sure if `a op= a op b` should have + /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. + /// If `a op= a op b` is really the correct behavior it should be + /// written as `a = a op a op b` as it's less confusing. + /// + /// ### Example + /// ```rust + /// let mut a = 5; + /// let b = 2; + /// // ... + /// a += a + b; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MISREFACTORED_ASSIGN_OP, + suspicious, + "having a variable on both sides of an assign op" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for incompatible bit masks in comparisons. + /// + /// The formula for detecting if an expression of the type `_ <bit_op> m + /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of + /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following + /// table: + /// + /// |Comparison |Bit Op|Example |is always|Formula | + /// |------------|------|-------------|---------|----------------------| + /// |`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | + /// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | + /// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | + /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` | + /// |`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` | + /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` | + /// + /// ### Why is this bad? + /// If the bits that the comparison cares about are always + /// set to zero or one by the bit mask, the comparison is constant `true` or + /// `false` (depending on mask, compared value, and operators). + /// + /// So the code is actively misleading, and the only reason someone would write + /// this intentionally is to win an underhanded Rust contest or create a + /// test-case for this lint. + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// if (x & 1 == 2) { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub BAD_BIT_MASK, + correctness, + "expressions of the form `_ & mask == select` that will only ever return `true` or `false`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for bit masks in comparisons which can be removed + /// without changing the outcome. The basic structure can be seen in the + /// following table: + /// + /// |Comparison| Bit Op |Example |equals | + /// |----------|----------|------------|-------| + /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`| + /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`| + /// + /// ### Why is this bad? + /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask), + /// but still a bit misleading, because the bit mask is ineffective. + /// + /// ### Known problems + /// False negatives: This lint will only match instances + /// where we have figured out the math (which is for a power-of-two compared + /// value). This means things like `x | 1 >= 7` (which would be better written + /// as `x >= 6`) will not be reported (but bit masks like this are fairly + /// uncommon). + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// if (x | 1 > 3) { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub INEFFECTIVE_BIT_MASK, + correctness, + "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for bit masks that can be replaced by a call + /// to `trailing_zeros` + /// + /// ### Why is this bad? + /// `x.trailing_zeros() > 4` is much clearer than `x & 15 + /// == 0` + /// + /// ### Known problems + /// llvm generates better code for `x & 15 == 0` on x86 + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// if x & 0b1111 == 0 { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub VERBOSE_BIT_MASK, + pedantic, + "expressions where a bit mask is less readable than the corresponding method call" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for double comparisons that could be simplified to a single expression. + /// + /// + /// ### Why is this bad? + /// Readability. + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// # let y = 2; + /// if x == y || x < y {} + /// ``` + /// + /// Use instead: + /// + /// ```rust + /// # let x = 1; + /// # let y = 2; + /// if x <= y {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DOUBLE_COMPARISONS, + complexity, + "unnecessary double comparisons that can be simplified" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for calculation of subsecond microseconds or milliseconds + /// from other `Duration` methods. + /// + /// ### Why is this bad? + /// It's more concise to call `Duration::subsec_micros()` or + /// `Duration::subsec_millis()` than to calculate them. + /// + /// ### Example + /// ```rust + /// # use std::time::Duration; + /// # let duration = Duration::new(5, 0); + /// let micros = duration.subsec_nanos() / 1_000; + /// let millis = duration.subsec_nanos() / 1_000_000; + /// ``` + /// + /// Use instead: + /// ```rust + /// # use std::time::Duration; + /// # let duration = Duration::new(5, 0); + /// let micros = duration.subsec_micros(); + /// let millis = duration.subsec_millis(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DURATION_SUBSEC, + complexity, + "checks for calculation of subsecond microseconds or milliseconds" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for equal operands to comparison, logical and + /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, + /// `||`, `&`, `|`, `^`, `-` and `/`). + /// + /// ### Why is this bad? + /// This is usually just a typo or a copy and paste error. + /// + /// ### Known problems + /// False negatives: We had some false positives regarding + /// calls (notably [racer](https://github.com/phildawes/racer) had one instance + /// of `x.pop() && x.pop()`), so we removed matching any function or method + /// calls. We may introduce a list of known pure functions in the future. + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// if x + 1 == x + 1 {} + /// + /// // or + /// + /// # let a = 3; + /// # let b = 4; + /// assert_eq!(a, a); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub EQ_OP, + correctness, + "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for arguments to `==` which have their address + /// taken to satisfy a bound + /// and suggests to dereference the other argument instead + /// + /// ### Why is this bad? + /// It is more idiomatic to dereference the other argument. + /// + /// ### Example + /// ```rust,ignore + /// &x == y + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// x == *y + /// ``` + #[clippy::version = "pre 1.29.0"] + pub OP_REF, + style, + "taking a reference to satisfy the type constraints on `==`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for erasing operations, e.g., `x * 0`. + /// + /// ### Why is this bad? + /// The whole expression can be replaced by zero. + /// This is most likely not the intended outcome and should probably be + /// corrected + /// + /// ### Example + /// ```rust + /// let x = 1; + /// 0 / x; + /// 0 * x; + /// x & 0; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub ERASING_OP, + correctness, + "using erasing operations, e.g., `x * 0` or `y & 0`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for statements of the form `(a - b) < f32::EPSILON` or + /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`. + /// + /// ### Why is this bad? + /// The code without `.abs()` is more likely to have a bug. + /// + /// ### Known problems + /// If the user can ensure that b is larger than a, the `.abs()` is + /// technically unnecessary. However, it will make the code more robust and doesn't have any + /// large performance implications. If the abs call was deliberately left out for performance + /// reasons, it is probably better to state this explicitly in the code, which then can be done + /// with an allow. + /// + /// ### Example + /// ```rust + /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { + /// (a - b) < f32::EPSILON + /// } + /// ``` + /// Use instead: + /// ```rust + /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { + /// (a - b).abs() < f32::EPSILON + /// } + /// ``` + #[clippy::version = "1.48.0"] + pub FLOAT_EQUALITY_WITHOUT_ABS, + suspicious, + "float equality check without `.abs()`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for identity operations, e.g., `x + 0`. + /// + /// ### Why is this bad? + /// This code can be removed without changing the + /// meaning. So it just obscures what's going on. Delete it mercilessly. + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// x / 1 + 0 * 1 - 0 | 0; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub IDENTITY_OP, + complexity, + "using identity operations, e.g., `x + 0` or `y / 1`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for division of integers + /// + /// ### Why is this bad? + /// When outside of some very specific algorithms, + /// integer division is very often a mistake because it discards the + /// remainder. + /// + /// ### Example + /// ```rust + /// let x = 3 / 2; + /// println!("{}", x); + /// ``` + /// + /// Use instead: + /// ```rust + /// let x = 3f32 / 2f32; + /// println!("{}", x); + /// ``` + #[clippy::version = "1.37.0"] + pub INTEGER_DIVISION, + restriction, + "integer division may cause loss of precision" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons to NaN. + /// + /// ### Why is this bad? + /// NaN does not compare meaningfully to anything – not + /// even itself – so those comparisons are simply wrong. + /// + /// ### Example + /// ```rust + /// # let x = 1.0; + /// if x == f32::NAN { } + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = 1.0f32; + /// if x.is_nan() { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub CMP_NAN, + correctness, + "comparisons to `NAN`, which will always return false, probably not intended" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for conversions to owned values just for the sake + /// of a comparison. + /// + /// ### Why is this bad? + /// The comparison can operate on a reference, so creating + /// an owned value effectively throws it away directly afterwards, which is + /// needlessly consuming code and heap space. + /// + /// ### Example + /// ```rust + /// # let x = "foo"; + /// # let y = String::from("foo"); + /// if x.to_owned() == y {} + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = "foo"; + /// # let y = String::from("foo"); + /// if x == y {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub CMP_OWNED, + perf, + "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for (in-)equality comparisons on floating-point + /// values (apart from zero), except in functions called `*eq*` (which probably + /// implement equality for a type involving floats). + /// + /// ### Why is this bad? + /// Floating point calculations are usually imprecise, so + /// asking if two values are *exactly* equal is asking for trouble. For a good + /// guide on what to do, see [the floating point + /// guide](http://www.floating-point-gui.de/errors/comparison). + /// + /// ### Example + /// ```rust + /// let x = 1.2331f64; + /// let y = 1.2332f64; + /// + /// if y == 1.23f64 { } + /// if y != x {} // where both are floats + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = 1.2331f64; + /// # let y = 1.2332f64; + /// let error_margin = f64::EPSILON; // Use an epsilon for comparison + /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. + /// // let error_margin = std::f64::EPSILON; + /// if (y - 1.23f64).abs() < error_margin { } + /// if (y - x).abs() > error_margin { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub FLOAT_CMP, + pedantic, + "using `==` or `!=` on float values instead of comparing difference with an epsilon" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for (in-)equality comparisons on floating-point + /// value and constant, except in functions called `*eq*` (which probably + /// implement equality for a type involving floats). + /// + /// ### Why is this bad? + /// Floating point calculations are usually imprecise, so + /// asking if two values are *exactly* equal is asking for trouble. For a good + /// guide on what to do, see [the floating point + /// guide](http://www.floating-point-gui.de/errors/comparison). + /// + /// ### Example + /// ```rust + /// let x: f64 = 1.0; + /// const ONE: f64 = 1.00; + /// + /// if x == ONE { } // where both are floats + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x: f64 = 1.0; + /// # const ONE: f64 = 1.00; + /// let error_margin = f64::EPSILON; // Use an epsilon for comparison + /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. + /// // let error_margin = std::f64::EPSILON; + /// if (x - ONE).abs() < error_margin { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub FLOAT_CMP_CONST, + restriction, + "using `==` or `!=` on float constants instead of comparing difference with an epsilon" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for getting the remainder of a division by one or minus + /// one. + /// + /// ### Why is this bad? + /// The result for a divisor of one can only ever be zero; for + /// minus one it can cause panic/overflow (if the left operand is the minimal value of + /// the respective integer type) or results in zero. No one will write such code + /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that + /// contest, it's probably a bad idea. Use something more underhanded. + /// + /// ### Example + /// ```rust + /// # let x = 1; + /// let a = x % 1; + /// let a = x % -1; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MODULO_ONE, + correctness, + "taking a number modulo +/-1, which can either panic/overflow or always returns 0" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for modulo arithmetic. + /// + /// ### Why is this bad? + /// The results of modulo (%) operation might differ + /// depending on the language, when negative numbers are involved. + /// If you interop with different languages it might be beneficial + /// to double check all places that use modulo arithmetic. + /// + /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. + /// + /// ### Example + /// ```rust + /// let x = -17 % 3; + /// ``` + #[clippy::version = "1.42.0"] + pub MODULO_ARITHMETIC, + restriction, + "any modulo arithmetic statement" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + /// a lazy and. + /// + /// ### Why is this bad? + /// The bitwise operators do not support short-circuiting, so it may hinder code performance. + /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` + /// + /// ### Known problems + /// This lint evaluates only when the right side is determined to have no side effects. At this time, that + /// determination is quite conservative. + /// + /// ### Example + /// ```rust + /// let (x,y) = (true, false); + /// if x & !y {} // where both x and y are booleans + /// ``` + /// Use instead: + /// ```rust + /// let (x,y) = (true, false); + /// if x && !y {} + /// ``` + #[clippy::version = "1.54.0"] + pub NEEDLESS_BITWISE_BOOL, + pedantic, + "Boolean expressions that use bitwise rather than lazy operators" +} + +declare_clippy_lint! { + /// ### What it does + /// Use `std::ptr::eq` when applicable + /// + /// ### Why is this bad? + /// `ptr::eq` can be used to compare `&T` references + /// (which coerce to `*const T` implicitly) by their address rather than + /// comparing the values they point to. + /// + /// ### Example + /// ```rust + /// let a = &[1, 2, 3]; + /// let b = &[1, 2, 3]; + /// + /// assert!(a as *const _ as usize == b as *const _ as usize); + /// ``` + /// Use instead: + /// ```rust + /// let a = &[1, 2, 3]; + /// let b = &[1, 2, 3]; + /// + /// assert!(std::ptr::eq(a, b)); + /// ``` + #[clippy::version = "1.49.0"] + pub PTR_EQ, + style, + "use `std::ptr::eq` when comparing raw pointers" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for explicit self-assignments. + /// + /// ### Why is this bad? + /// Self-assignments are redundant and unlikely to be + /// intentional. + /// + /// ### Known problems + /// If expression contains any deref coercions or + /// indexing operations they are assumed not to have any side effects. + /// + /// ### Example + /// ```rust + /// struct Event { + /// x: i32, + /// } + /// + /// fn copy_position(a: &mut Event, b: &Event) { + /// a.x = a.x; + /// } + /// ``` + /// + /// Should be: + /// ```rust + /// struct Event { + /// x: i32, + /// } + /// + /// fn copy_position(a: &mut Event, b: &Event) { + /// a.x = b.x; + /// } + /// ``` + #[clippy::version = "1.48.0"] + pub SELF_ASSIGNMENT, + correctness, + "explicit self-assignment" +} + +pub struct Operators { + arithmetic_context: numeric_arithmetic::Context, + verbose_bit_mask_threshold: u64, +} +impl_lint_pass!(Operators => [ + ABSURD_EXTREME_COMPARISONS, + INTEGER_ARITHMETIC, + FLOAT_ARITHMETIC, + ASSIGN_OP_PATTERN, + MISREFACTORED_ASSIGN_OP, + BAD_BIT_MASK, + INEFFECTIVE_BIT_MASK, + VERBOSE_BIT_MASK, + DOUBLE_COMPARISONS, + DURATION_SUBSEC, + EQ_OP, + OP_REF, + ERASING_OP, + FLOAT_EQUALITY_WITHOUT_ABS, + IDENTITY_OP, + INTEGER_DIVISION, + CMP_NAN, + CMP_OWNED, + FLOAT_CMP, + FLOAT_CMP_CONST, + MODULO_ONE, + MODULO_ARITHMETIC, + NEEDLESS_BITWISE_BOOL, + PTR_EQ, + SELF_ASSIGNMENT, +]); +impl Operators { + pub fn new(verbose_bit_mask_threshold: u64) -> Self { + Self { + arithmetic_context: numeric_arithmetic::Context::default(), + verbose_bit_mask_threshold, + } + } +} +impl<'tcx> LateLintPass<'tcx> for Operators { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + eq_op::check_assert(cx, e); + match e.kind { + ExprKind::Binary(op, lhs, rhs) => { + if !e.span.from_expansion() { + absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs); + if !(macro_with_not_op(lhs) || macro_with_not_op(rhs)) { + eq_op::check(cx, e, op.node, lhs, rhs); + op_ref::check(cx, e, op.node, lhs, rhs); + } + erasing_op::check(cx, e, op.node, lhs, rhs); + identity_op::check(cx, e, op.node, lhs, rhs); + needless_bitwise_bool::check(cx, e, op.node, lhs, rhs); + ptr_eq::check(cx, e, op.node, lhs, rhs); + } + self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); + bit_mask::check(cx, e, op.node, lhs, rhs); + verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold); + double_comparison::check(cx, op.node, lhs, rhs, e.span); + duration_subsec::check(cx, e, op.node, lhs, rhs); + float_equality_without_abs::check(cx, e, op.node, lhs, rhs); + integer_division::check(cx, e, op.node, lhs, rhs); + cmp_nan::check(cx, e, op.node, lhs, rhs); + cmp_owned::check(cx, op.node, lhs, rhs); + float_cmp::check(cx, e, op.node, lhs, rhs); + modulo_one::check(cx, e, op.node, rhs); + modulo_arithmetic::check(cx, e, op.node, lhs, rhs); + }, + ExprKind::AssignOp(op, lhs, rhs) => { + self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); + misrefactored_assign_op::check(cx, e, op.node, lhs, rhs); + modulo_arithmetic::check(cx, e, op.node, lhs, rhs); + }, + ExprKind::Assign(lhs, rhs, _) => { + assign_op_pattern::check(cx, e, lhs, rhs); + self_assignment::check(cx, e, lhs, rhs); + }, + ExprKind::Unary(op, arg) => { + if op == UnOp::Neg { + self.arithmetic_context.check_negate(cx, e, arg); + } + }, + _ => (), + } + } + + fn check_expr_post(&mut self, _: &LateContext<'_>, e: &Expr<'_>) { + self.arithmetic_context.expr_post(e.hir_id); + } + + fn check_body(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) { + self.arithmetic_context.enter_body(cx, b); + } + + fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) { + self.arithmetic_context.body_post(cx, b); + } +} + +fn macro_with_not_op(e: &Expr<'_>) -> bool { + if let ExprKind::Unary(_, e) = e.kind { + e.span.from_expansion() + } else { + false + } +} diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs similarity index 64% rename from src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs rename to src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index 195b2e5c2ee0a..af4e74947f41d 100644 --- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -2,35 +2,35 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sext; use if_chain::if_chain; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::{BinOpKind, Expr}; +use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; -declare_clippy_lint! { - /// ### What it does - /// Checks for modulo arithmetic. - /// - /// ### Why is this bad? - /// The results of modulo (%) operation might differ - /// depending on the language, when negative numbers are involved. - /// If you interop with different languages it might be beneficial - /// to double check all places that use modulo arithmetic. - /// - /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. - /// - /// ### Example - /// ```rust - /// let x = -17 % 3; - /// ``` - #[clippy::version = "1.42.0"] - pub MODULO_ARITHMETIC, - restriction, - "any modulo arithmetic statement" -} +use super::MODULO_ARITHMETIC; -declare_lint_pass!(ModuloArithmetic => [MODULO_ARITHMETIC]); +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + lhs: &'tcx Expr<'_>, + rhs: &'tcx Expr<'_>, +) { + if op == BinOpKind::Rem { + let lhs_operand = analyze_operand(lhs, cx, e); + let rhs_operand = analyze_operand(rhs, cx, e); + if_chain! { + if let Some(lhs_operand) = lhs_operand; + if let Some(rhs_operand) = rhs_operand; + then { + check_const_operands(cx, e, &lhs_operand, &rhs_operand); + } + else { + check_non_const_operands(cx, e, lhs); + } + } + }; +} struct OperandInfo { string_representation: Option<String>, @@ -124,27 +124,3 @@ fn check_non_const_operands<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ); } } - -impl<'tcx> LateLintPass<'tcx> for ModuloArithmetic { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - match &expr.kind { - ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { - if op.node == BinOpKind::Rem { - let lhs_operand = analyze_operand(lhs, cx, expr); - let rhs_operand = analyze_operand(rhs, cx, expr); - if_chain! { - if let Some(lhs_operand) = lhs_operand; - if let Some(rhs_operand) = rhs_operand; - then { - check_const_operands(cx, expr, &lhs_operand, &rhs_operand); - } - else { - check_non_const_operands(cx, expr, lhs); - } - } - }; - }, - _ => {}, - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs new file mode 100644 index 0000000000000..54eea14833ffe --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs @@ -0,0 +1,26 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::{is_integer_const, unsext}; +use rustc_hir::{BinOpKind, Expr}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +use super::MODULO_ONE; + +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, right: &Expr<'_>) { + if op == BinOpKind::Rem { + if is_integer_const(cx, right, 1) { + span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + } + + if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { + if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { + span_lint( + cx, + MODULO_ONE, + expr.span, + "any number modulo -1 will panic/overflow or result in 0", + ); + } + }; + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs new file mode 100644 index 0000000000000..e902235a014e8 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -0,0 +1,36 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::NEEDLESS_BITWISE_BOOL; + +pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Expr<'_>, rhs: &Expr<'_>) { + let op_str = match op { + BinOpKind::BitAnd => "&&", + BinOpKind::BitOr => "||", + _ => return, + }; + if matches!( + rhs.kind, + ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) + ) && cx.typeck_results().expr_ty(e).is_bool() + && !rhs.can_have_side_effects() + { + span_lint_and_then( + cx, + NEEDLESS_BITWISE_BOOL, + e.span, + "use of bitwise operator instead of lazy operator between booleans", + |diag| { + if let Some(lhs_snip) = snippet_opt(cx, lhs.span) + && let Some(rhs_snip) = snippet_opt(cx, rhs.span) + { + let sugg = format!("{} {} {}", lhs_snip, op_str, rhs_snip); + diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); + } + }, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs new file mode 100644 index 0000000000000..b6097710dc689 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -0,0 +1,128 @@ +use clippy_utils::consts::constant_simple; +use clippy_utils::diagnostics::span_lint; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}; + +#[derive(Default)] +pub struct Context { + expr_id: Option<hir::HirId>, + /// This field is used to check whether expressions are constants, such as in enum discriminants + /// and consts + const_span: Option<Span>, +} +impl Context { + fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool { + self.expr_id.is_some() || self.const_span.map_or(false, |span| span.contains(e.span)) + } + + pub fn check_binary<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + op: hir::BinOpKind, + l: &'tcx hir::Expr<'_>, + r: &'tcx hir::Expr<'_>, + ) { + if self.skip_expr(expr) { + return; + } + match op { + hir::BinOpKind::And + | hir::BinOpKind::Or + | hir::BinOpKind::BitAnd + | hir::BinOpKind::BitOr + | hir::BinOpKind::BitXor + | hir::BinOpKind::Eq + | hir::BinOpKind::Lt + | hir::BinOpKind::Le + | hir::BinOpKind::Ne + | hir::BinOpKind::Ge + | hir::BinOpKind::Gt => return, + _ => (), + } + + let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); + if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { + match op { + hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { + hir::ExprKind::Lit(_lit) => (), + hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { + if let hir::ExprKind::Lit(lit) = &expr.kind { + if let rustc_ast::ast::LitKind::Int(1, _) = lit.node { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_id = Some(expr.hir_id); + } + } + }, + _ => { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_id = Some(expr.hir_id); + }, + }, + _ => { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_id = Some(expr.hir_id); + }, + } + } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { + span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); + self.expr_id = Some(expr.hir_id); + } + } + + pub fn check_negate<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { + if self.skip_expr(expr) { + return; + } + let ty = cx.typeck_results().expr_ty(arg); + if constant_simple(cx, cx.typeck_results(), expr).is_none() { + if ty.is_integral() { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_id = Some(expr.hir_id); + } else if ty.is_floating_point() { + span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); + self.expr_id = Some(expr.hir_id); + } + } + } + + pub fn expr_post(&mut self, id: hir::HirId) { + if Some(id) == self.expr_id { + self.expr_id = None; + } + } + + pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { + let body_owner = cx.tcx.hir().body_owner(body.id()); + let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner); + + match cx.tcx.hir().body_owner_kind(body_owner_def_id) { + hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => { + let body_span = cx.tcx.hir().span_with_body(body_owner); + + if let Some(span) = self.const_span { + if span.contains(body_span) { + return; + } + } + self.const_span = Some(body_span); + }, + hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (), + } + } + + pub fn body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { + let body_owner = cx.tcx.hir().body_owner(body.id()); + let body_span = cx.tcx.hir().span_with_body(body_owner); + + if let Some(span) = self.const_span { + if span.contains(body_span) { + return; + } + } + self.const_span = None; + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs new file mode 100644 index 0000000000000..1805672e37254 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs @@ -0,0 +1,218 @@ +use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; +use clippy_utils::get_enclosing_block; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, is_copy}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; + +use super::OP_REF; + +#[expect(clippy::similar_names, clippy::too_many_lines)] +pub(crate) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + let (trait_id, requires_ref) = match op { + BinOpKind::Add => (cx.tcx.lang_items().add_trait(), false), + BinOpKind::Sub => (cx.tcx.lang_items().sub_trait(), false), + BinOpKind::Mul => (cx.tcx.lang_items().mul_trait(), false), + BinOpKind::Div => (cx.tcx.lang_items().div_trait(), false), + BinOpKind::Rem => (cx.tcx.lang_items().rem_trait(), false), + // don't lint short circuiting ops + BinOpKind::And | BinOpKind::Or => return, + BinOpKind::BitXor => (cx.tcx.lang_items().bitxor_trait(), false), + BinOpKind::BitAnd => (cx.tcx.lang_items().bitand_trait(), false), + BinOpKind::BitOr => (cx.tcx.lang_items().bitor_trait(), false), + BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false), + BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false), + BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true), + BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => { + (cx.tcx.lang_items().partial_ord_trait(), true) + }, + }; + if let Some(trait_id) = trait_id { + match (&left.kind, &right.kind) { + // do not suggest to dereference literals + (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {}, + // &foo == &bar + (&ExprKind::AddrOf(BorrowKind::Ref, _, l), &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { + let lty = cx.typeck_results().expr_ty(l); + let rty = cx.typeck_results().expr_ty(r); + let lcpy = is_copy(cx, lty); + let rcpy = is_copy(cx, rty); + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { + if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) + { + return; // Don't lint + } + } + // either operator autorefs or both args are copyable + if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) { + span_lint_and_then( + cx, + OP_REF, + e.span, + "needlessly taken reference of both operands", + |diag| { + let lsnip = snippet(cx, l.span, "...").to_string(); + let rsnip = snippet(cx, r.span, "...").to_string(); + multispan_sugg( + diag, + "use the values directly", + vec![(left.span, lsnip), (right.span, rsnip)], + ); + }, + ); + } else if lcpy + && !rcpy + && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) + { + span_lint_and_then( + cx, + OP_REF, + e.span, + "needlessly taken reference of left operand", + |diag| { + let lsnip = snippet(cx, l.span, "...").to_string(); + diag.span_suggestion( + left.span, + "use the left value directly", + lsnip, + Applicability::MaybeIncorrect, // FIXME #2597 + ); + }, + ); + } else if !lcpy + && rcpy + && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) + { + span_lint_and_then( + cx, + OP_REF, + e.span, + "needlessly taken reference of right operand", + |diag| { + let rsnip = snippet(cx, r.span, "...").to_string(); + diag.span_suggestion( + right.span, + "use the right value directly", + rsnip, + Applicability::MaybeIncorrect, // FIXME #2597 + ); + }, + ); + } + }, + // &foo == bar + (&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => { + let lty = cx.typeck_results().expr_ty(l); + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { + let rty = cx.typeck_results().expr_ty(right); + if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) + { + return; // Don't lint + } + } + let lcpy = is_copy(cx, lty); + if (requires_ref || lcpy) + && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) + { + span_lint_and_then( + cx, + OP_REF, + e.span, + "needlessly taken reference of left operand", + |diag| { + let lsnip = snippet(cx, l.span, "...").to_string(); + diag.span_suggestion( + left.span, + "use the left value directly", + lsnip, + Applicability::MaybeIncorrect, // FIXME #2597 + ); + }, + ); + } + }, + // foo == &bar + (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => { + let rty = cx.typeck_results().expr_ty(r); + if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) { + let lty = cx.typeck_results().expr_ty(left); + if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty)) + || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)) + { + return; // Don't lint + } + } + let rcpy = is_copy(cx, rty); + if (requires_ref || rcpy) + && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) + { + span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| { + let rsnip = snippet(cx, r.span, "...").to_string(); + diag.span_suggestion( + right.span, + "use the right value directly", + rsnip, + Applicability::MaybeIncorrect, // FIXME #2597 + ); + }); + } + }, + _ => {}, + } + } +} + +fn in_impl<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + bin_op: DefId, +) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { + if_chain! { + if let Some(block) = get_enclosing_block(cx, e.hir_id); + if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()); + let item = cx.tcx.hir().expect_item(impl_def_id.expect_local()); + if let ItemKind::Impl(item) = &item.kind; + if let Some(of_trait) = &item.of_trait; + if let Some(seg) = of_trait.path.segments.last(); + if let Some(Res::Def(_, trait_id)) = seg.res; + if trait_id == bin_op; + if let Some(generic_args) = seg.args; + if let Some(GenericArg::Type(other_ty)) = generic_args.args.last(); + + then { + Some((item.self_ty, other_ty)) + } + else { + None + } + } +} + +fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { + if_chain! { + if let ty::Adt(adt_def, _) = middle_ty.kind(); + if let Some(local_did) = adt_def.did().as_local(); + let item = cx.tcx.hir().expect_item(local_did); + let middle_ty_id = item.def_id.to_def_id(); + if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; + if let Res::Def(_, hir_ty_id) = path.res; + + then { + hir_ty_id == middle_ty_id + } + else { + false + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs new file mode 100644 index 0000000000000..1aefc2741c21c --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs @@ -0,0 +1,65 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::PTR_EQ; + +static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, +) { + if BinOpKind::Eq == op { + let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { + (Some(lhs), Some(rhs)) => (lhs, rhs), + _ => (left, right), + }; + + if_chain! { + if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); + if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); + if let Some(left_snip) = snippet_opt(cx, left_var.span); + if let Some(right_snip) = snippet_opt(cx, right_var.span); + then { + span_lint_and_sugg( + cx, + PTR_EQ, + expr.span, + LINT_MSG, + "try", + format!("std::ptr::eq({}, {})", left_snip, right_snip), + Applicability::MachineApplicable, + ); + } + } + } +} + +// If the given expression is a cast to a usize, return the lhs of the cast +// E.g., `foo as *const _ as usize` returns `foo as *const _`. +fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize { + if let ExprKind::Cast(expr, _) = cast_expr.kind { + return Some(expr); + } + } + None +} + +// If the given expression is a cast to a `*const` pointer, return the lhs of the cast +// E.g., `foo as *const _` returns `foo`. +fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() { + if let ExprKind::Cast(expr, _) = cast_expr.kind { + return Some(expr); + } + } + None +} diff --git a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs new file mode 100644 index 0000000000000..9d6bec05bf095 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs @@ -0,0 +1,20 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::eq_expr_value; +use clippy_utils::source::snippet; +use rustc_hir::Expr; +use rustc_lint::LateContext; + +use super::SELF_ASSIGNMENT; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>) { + if eq_expr_value(cx, lhs, rhs) { + let lhs = snippet(cx, lhs.span, "<lhs>"); + let rhs = snippet(cx, rhs.span, "<rhs>"); + span_lint( + cx, + SELF_ASSIGNMENT, + e.span, + &format!("self-assignment of `{}` to `{}`", rhs, lhs), + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs new file mode 100644 index 0000000000000..ff85fd5542988 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs @@ -0,0 +1,44 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::VERBOSE_BIT_MASK; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, + threshold: u64, +) { + if BinOpKind::Eq == op + && let ExprKind::Binary(op1, left1, right1) = &left.kind + && BinOpKind::BitAnd == op1.node + && let ExprKind::Lit(lit) = &right1.kind + && let LitKind::Int(n, _) = lit.node + && let ExprKind::Lit(lit1) = &right.kind + && let LitKind::Int(0, _) = lit1.node + && n.leading_zeros() == n.count_zeros() + && n > u128::from(threshold) + { + span_lint_and_then( + cx, + VERBOSE_BIT_MASK, + e.span, + "bit mask could be simplified with a call to `trailing_zeros`", + |diag| { + let sugg = Sugg::hir(cx, left1, "...").maybe_par(); + diag.span_suggestion( + e.span, + "try", + format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()), + Applicability::MaybeIncorrect, + ); + }, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 05ab62786f409..5fa4fd74853f1 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -3,17 +3,20 @@ use std::iter; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::is_copy; +use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{is_self, is_self_ty}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_ast::attr; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::adjustment::{Adjust, PointerCast}; use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, RegionKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -141,50 +144,76 @@ impl<'tcx> PassByRefOrValue { } let fn_sig = cx.tcx.fn_sig(def_id); - let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig); - let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id)); - for (index, (input, &ty)) in iter::zip(decl.inputs, fn_sig.inputs()).enumerate() { + // Gather all the lifetimes found in the output type which may affect whether + // `TRIVIALLY_COPY_PASS_BY_REF` should be linted. + let mut output_regions = FxHashSet::default(); + for_each_top_level_late_bound_region(fn_sig.skip_binder().output(), |region| -> ControlFlow<!> { + output_regions.insert(region); + ControlFlow::Continue(()) + }); + + for (index, (input, ty)) in iter::zip( + decl.inputs, + fn_sig.skip_binder().inputs().iter().map(|&ty| fn_sig.rebind(ty)), + ) + .enumerate() + { // All spans generated from a proc-macro invocation are the same... match span { - Some(s) if s == input.span => return, + Some(s) if s == input.span => continue, _ => (), } - match ty.kind() { - ty::Ref(input_lt, ty, Mutability::Not) => { - // Use lifetimes to determine if we're returning a reference to the - // argument. In that case we can't switch to pass-by-value as the - // argument will not live long enough. - let output_lts = match *fn_sig.output().kind() { - ty::Ref(output_lt, _, _) => vec![output_lt], - ty::Adt(_, substs) => substs.regions().collect(), - _ => vec![], - }; + match *ty.skip_binder().kind() { + ty::Ref(lt, ty, Mutability::Not) => { + match lt.kind() { + RegionKind::ReLateBound(index, region) + if index.as_u32() == 0 && output_regions.contains(®ion) => + { + continue; + }, + // Early bound regions on functions are either from the containing item, are bounded by another + // lifetime, or are used as a bound for a type or lifetime. + RegionKind::ReEarlyBound(..) => continue, + _ => (), + } - if_chain! { - if !output_lts.contains(input_lt); - if is_copy(cx, *ty); - if let Some(size) = cx.layout_of(*ty).ok().map(|l| l.size.bytes()); - if size <= self.ref_min_size; - if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind; - then { - let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) { - "self".into() - } else { - snippet(cx, decl_ty.span, "_").into() - }; - span_lint_and_sugg( - cx, - TRIVIALLY_COPY_PASS_BY_REF, - input.span, - &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size), - "consider passing by value instead", - value_type, - Applicability::Unspecified, - ); + let ty = cx.tcx.erase_late_bound_regions(fn_sig.rebind(ty)); + if is_copy(cx, ty) + && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) + && size <= self.ref_min_size + && let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind + { + if let Some(typeck) = cx.maybe_typeck_results() { + // Don't lint if an unsafe pointer is created. + // TODO: Limit the check only to unsafe pointers to the argument (or part of the argument) + // which escape the current function. + if typeck.node_types().iter().any(|(_, &ty)| ty.is_unsafe_ptr()) + || typeck + .adjustments() + .iter() + .flat_map(|(_, a)| a) + .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer))) + { + continue; + } } + let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) { + "self".into() + } else { + snippet(cx, decl_ty.span, "_").into() + }; + span_lint_and_sugg( + cx, + TRIVIALLY_COPY_PASS_BY_REF, + input.span, + &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size), + "consider passing by value instead", + value_type, + Applicability::Unspecified, + ); } }, @@ -196,6 +225,7 @@ impl<'tcx> PassByRefOrValue { _ => continue, } } + let ty = cx.tcx.erase_late_bound_regions(ty); if_chain! { if is_copy(cx, ty); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index b06eba13d2fdb..8571607054a00 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -1,6 +1,6 @@ //! Checks for usage of `&Vec[_]` and `&String`. -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; @@ -166,15 +166,14 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { ) .filter(|arg| arg.mutability() == Mutability::Not) { - span_lint_and_sugg( - cx, - PTR_ARG, - arg.span, - &arg.build_msg(), - "change this to", - format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)), - Applicability::Unspecified, - ); + span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, &arg.build_msg(), |diag| { + diag.span_suggestion( + arg.span, + "change this to", + format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)), + Applicability::Unspecified, + ); + }); } } } @@ -221,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { let results = check_ptr_arg_usage(cx, body, &lint_args); for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { - span_lint_and_then(cx, PTR_ARG, args.span, &args.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, &args.build_msg(), |diag| { diag.multipart_suggestion( "change this to", iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx)))) @@ -315,6 +314,7 @@ struct PtrArgReplacement { struct PtrArg<'tcx> { idx: usize, + emission_id: hir::HirId, span: Span, ty_did: DefId, ty_name: Symbol, @@ -419,10 +419,8 @@ fn check_fn_args<'cx, 'tcx: 'cx>( if let [.., name] = path.segments; if cx.tcx.item_name(adt.did()) == name.ident.name; - if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id); - if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id)); - then { + let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( [("clone", ".to_owned()")].as_slice(), @@ -455,14 +453,20 @@ fn check_fn_args<'cx, 'tcx: 'cx>( }) .and_then(|arg| snippet_opt(cx, arg.span)) .unwrap_or_else(|| substs.type_at(1).to_string()); - span_lint_and_sugg( + span_lint_hir_and_then( cx, PTR_ARG, + emission_id, hir_ty.span, "using a reference to `Cow` is not recommended", - "change this to", - format!("&{}{}", mutability.prefix_str(), ty_name), - Applicability::Unspecified, + |diag| { + diag.span_suggestion( + hir_ty.span, + "change this to", + format!("&{}{}", mutability.prefix_str(), ty_name), + Applicability::Unspecified, + ); + } ); return None; }, @@ -470,6 +474,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( }; return Some(PtrArg { idx: i, + emission_id, span: hir_ty.span, ty_did: adt.did(), ty_name: name.ident.name, @@ -490,12 +495,13 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio if let FnRetTy::Return(ty) = sig.decl.output && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) { + let out_region = cx.tcx.named_region(out.hir_id); let args: Option<Vec<_>> = sig .decl .inputs .iter() .filter_map(get_rptr_lm) - .filter(|&(lt, _, _)| lt.name == out.name) + .filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region) .map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span)) .collect(); if let Some(args) = args @@ -574,14 +580,13 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: Some((Node::Expr(e), child_id)) => match e.kind { ExprKind::Call(f, expr_args) => { let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); - if expr_sig(self.cx, f) - .map(|sig| sig.input(i).skip_binder().peel_refs()) - .map_or(true, |ty| match *ty.kind() { + if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| { + match *ty.skip_binder().peel_refs().kind() { ty::Param(_) => true, ty::Adt(def, _) => def.did() == args.ty_did, _ => false, - }) - { + } + }) { // Passed to a function taking the non-dereferenced type. set_skip_flag(); } diff --git a/src/tools/clippy/clippy_lints/src/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/ptr_eq.rs deleted file mode 100644 index 2bec93ac60605..0000000000000 --- a/src/tools/clippy/clippy_lints/src/ptr_eq.rs +++ /dev/null @@ -1,97 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Use `std::ptr::eq` when applicable - /// - /// ### Why is this bad? - /// `ptr::eq` can be used to compare `&T` references - /// (which coerce to `*const T` implicitly) by their address rather than - /// comparing the values they point to. - /// - /// ### Example - /// ```rust - /// let a = &[1, 2, 3]; - /// let b = &[1, 2, 3]; - /// - /// assert!(a as *const _ as usize == b as *const _ as usize); - /// ``` - /// Use instead: - /// ```rust - /// let a = &[1, 2, 3]; - /// let b = &[1, 2, 3]; - /// - /// assert!(std::ptr::eq(a, b)); - /// ``` - #[clippy::version = "1.49.0"] - pub PTR_EQ, - style, - "use `std::ptr::eq` when comparing raw pointers" -} - -declare_lint_pass!(PtrEq => [PTR_EQ]); - -static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers"; - -impl<'tcx> LateLintPass<'tcx> for PtrEq { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if expr.span.from_expansion() { - return; - } - - if let ExprKind::Binary(ref op, left, right) = expr.kind { - if BinOpKind::Eq == op.node { - let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { - (Some(lhs), Some(rhs)) => (lhs, rhs), - _ => (left, right), - }; - - if_chain! { - if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left); - if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right); - if let Some(left_snip) = snippet_opt(cx, left_var.span); - if let Some(right_snip) = snippet_opt(cx, right_var.span); - then { - span_lint_and_sugg( - cx, - PTR_EQ, - expr.span, - LINT_MSG, - "try", - format!("std::ptr::eq({}, {})", left_snip, right_snip), - Applicability::MachineApplicable, - ); - } - } - } - } - } -} - -// If the given expression is a cast to a usize, return the lhs of the cast -// E.g., `foo as *const _ as usize` returns `foo as *const _`. -fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize { - if let ExprKind::Cast(expr, _) = cast_expr.kind { - return Some(expr); - } - } - None -} - -// If the given expression is a cast to a `*const` pointer, return the lhs of the cast -// E.g., `foo as *const _` returns `foo`. -fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() { - if let ExprKind::Cast(expr, _) = cast_expr.kind { - return Some(expr); - } - } - None -} diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 3b11cbc376062..eddca60457574 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::{ visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, Mutability, }; -use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; +use rustc_middle::ty::{self, visit::TypeVisitor, Ty}; use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; @@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { // `arg` is a reference as it is `.deref()`ed in the previous block. // Look into the predecessor block and find out the source of deref. - let ps = &mir.predecessors()[bb]; + let ps = &mir.basic_blocks.predecessors()[bb]; if ps.len() != 1 { continue; } diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 65ed798867d19..f5a93cebab8ca 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall { if_chain! { if let ast::ExprKind::Call(ref paren, _) = expr.kind; if let ast::ExprKind::Paren(ref closure) = paren.kind; - if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind; + if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind; then { let mut visitor = ReturnVisitor::new(); visitor.visit_expr(block); diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index 0825f00f421c5..f8801f769e83d 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -87,7 +87,7 @@ impl RedundantStaticLifetimes { _ => {}, } } - self.visit_type(&*borrow_type.ty, cx, reason); + self.visit_type(&borrow_type.ty, cx, reason); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index e525eba53e2aa..1d9a2abf7066c 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::{fn_def_id, path_to_local_id}; use if_chain::if_chain; @@ -10,7 +10,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::sym; @@ -94,9 +93,10 @@ impl<'tcx> LateLintPass<'tcx> for Return { if !in_external_macro(cx.sess(), retexpr.span); if !local.span.from_expansion(); then { - span_lint_and_then( + span_lint_hir_and_then( cx, LET_AND_RETURN, + retexpr.hir_id, retexpr.span, "returning the result of a `let` binding from a block", |err| { @@ -185,6 +185,7 @@ fn check_final_expr<'tcx>( if !borrows { emit_return_lint( cx, + inner.map_or(expr.hir_id, |inner| inner.hir_id), span.expect("`else return` is not possible"), inner.as_ref().map(|i| i.span), replacement, @@ -201,9 +202,7 @@ fn check_final_expr<'tcx>( check_block_return(cx, ifblock); } if let Some(else_clause) = else_clause_opt { - if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) { - check_final_expr(cx, else_clause, None, RetReplacement::Empty); - } + check_final_expr(cx, else_clause, None, RetReplacement::Empty); } }, // a match expr, check all arms @@ -220,50 +219,81 @@ fn check_final_expr<'tcx>( } } -fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) { +fn emit_return_lint( + cx: &LateContext<'_>, + emission_place: HirId, + ret_span: Span, + inner_span: Option<Span>, + replacement: RetReplacement, +) { if ret_span.from_expansion() { return; } match inner_span { Some(inner_span) => { let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| { - let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); - diag.span_suggestion(ret_span, "remove `return`", snippet, applicability); - }); + span_lint_hir_and_then( + cx, + NEEDLESS_RETURN, + emission_place, + ret_span, + "unneeded `return` statement", + |diag| { + let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability); + diag.span_suggestion(ret_span, "remove `return`", snippet, applicability); + }, + ); }, None => match replacement { RetReplacement::Empty => { - span_lint_and_sugg( + span_lint_hir_and_then( cx, NEEDLESS_RETURN, + emission_place, ret_span, "unneeded `return` statement", - "remove `return`", - String::new(), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion( + ret_span, + "remove `return`", + String::new(), + Applicability::MachineApplicable, + ); + }, ); }, RetReplacement::Block => { - span_lint_and_sugg( + span_lint_hir_and_then( cx, NEEDLESS_RETURN, + emission_place, ret_span, "unneeded `return` statement", - "replace `return` with an empty block", - "{}".to_string(), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion( + ret_span, + "replace `return` with an empty block", + "{}".to_string(), + Applicability::MachineApplicable, + ); + }, ); }, RetReplacement::Unit => { - span_lint_and_sugg( + span_lint_hir_and_then( cx, NEEDLESS_RETURN, + emission_place, ret_span, "unneeded `return` statement", - "replace `return` with a unit value", - "()".to_string(), - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion( + ret_span, + "replace `return` with a unit value", + "()".to_string(), + Applicability::MachineApplicable, + ); + }, ); }, }, diff --git a/src/tools/clippy/clippy_lints/src/self_assignment.rs b/src/tools/clippy/clippy_lints/src/self_assignment.rs deleted file mode 100644 index b14f0518bdb77..0000000000000 --- a/src/tools/clippy/clippy_lints/src/self_assignment.rs +++ /dev/null @@ -1,56 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::eq_expr_value; -use clippy_utils::source::snippet; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for explicit self-assignments. - /// - /// ### Why is this bad? - /// Self-assignments are redundant and unlikely to be - /// intentional. - /// - /// ### Known problems - /// If expression contains any deref coercions or - /// indexing operations they are assumed not to have any side effects. - /// - /// ### Example - /// ```rust - /// struct Event { - /// id: usize, - /// x: i32, - /// y: i32, - /// } - /// - /// fn copy_position(a: &mut Event, b: &Event) { - /// a.x = b.x; - /// a.y = a.y; - /// } - /// ``` - #[clippy::version = "1.48.0"] - pub SELF_ASSIGNMENT, - correctness, - "explicit self-assignment" -} - -declare_lint_pass!(SelfAssignment => [SELF_ASSIGNMENT]); - -impl<'tcx> LateLintPass<'tcx> for SelfAssignment { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Assign(lhs, rhs, _) = &expr.kind { - if eq_expr_value(cx, lhs, rhs) { - let lhs = snippet(cx, lhs.span, "<lhs>"); - let rhs = snippet(cx, rhs.span, "<rhs>"); - span_lint( - cx, - SELF_ASSIGNMENT, - expr.span, - &format!("self-assignment of `{}` to `{}`", rhs, lhs), - ); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 975a0a06e3885..2c8aa17e80dbd 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -26,6 +26,9 @@ declare_clippy_lint! { /// let mut vec1 = Vec::with_capacity(len); /// vec1.resize(len, 0); /// + /// let mut vec1 = Vec::with_capacity(len); + /// vec1.resize(vec1.capacity(), 0); + /// /// let mut vec2 = Vec::with_capacity(len); /// vec2.extend(repeat(0).take(len)); /// ``` @@ -211,23 +214,20 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Checks if the given expression is resizing a vector with 0 fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { - if_chain! { - if self.initialization_found; - if let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind; - if path_to_local_id(self_arg, self.vec_alloc.local_id); - if path.ident.name == sym!(resize); - + if self.initialization_found + && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind + && path_to_local_id(self_arg, self.vec_alloc.local_id) + && path.ident.name == sym!(resize) // Check that is filled with 0 - if let ExprKind::Lit(ref lit) = fill_arg.kind; - if let LitKind::Int(0, _) = lit.node; - - // Check that len expression is equals to `with_capacity` expression - if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr); - - then { - self.slow_expression = Some(InitializationType::Resize(expr)); + && let ExprKind::Lit(ref lit) = fill_arg.kind + && let LitKind::Int(0, _) = lit.node { + // Check that len expression is equals to `with_capacity` expression + if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { + self.slow_expression = Some(InitializationType::Resize(expr)); + } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" { + self.slow_expression = Some(InitializationType::Resize(expr)); + } } - } } /// Returns `true` if give expression is `repeat(0).take(...)` @@ -240,12 +240,15 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { if let Some(repeat_expr) = take_args.get(0); if self.is_repeat_zero(repeat_expr); - // Check that len expression is equals to `with_capacity` expression if let Some(len_arg) = take_args.get(1); - if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr); then { - return true; + // Check that len expression is equals to `with_capacity` expression + if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { + return true; + } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" { + return true; + } } } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 71f3e6b6a6ec6..eb704a07451ca 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -60,6 +60,12 @@ declare_clippy_lint! { /// let x = "Hello".to_owned(); /// x + ", World"; /// ``` + /// + /// Use instead: + /// ```rust + /// let mut x = "Hello".to_owned(); + /// x.push_str(", World"); + /// ``` #[clippy::version = "pre 1.29.0"] pub STRING_ADD, restriction, diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index c4c1aa11004ac..fe8859905953f 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -582,7 +582,7 @@ fn ident_difference_expr_with_base_location( | (Await(_), Await(_)) | (Async(_, _, _), Async(_, _, _)) | (Block(_, _), Block(_, _)) - | (Closure(_, _, _, _, _, _), Closure(_, _, _, _, _, _)) + | (Closure(_, _, _, _, _, _, _), Closure(_, _, _, _, _, _, _)) | (Match(_, _), Match(_, _)) | (Loop(_, _), Loop(_, _)) | (ForLoop(_, _, _, _), ForLoop(_, _, _, _)) diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index cbe1406728bc7..5f3e98144f42d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -16,9 +16,10 @@ mod wrong_transmute; use clippy_utils::in_constant; use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_semver::RustcVersion; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; declare_clippy_lint! { @@ -385,7 +386,10 @@ declare_clippy_lint! { "transmute to or from a type with an undefined representation" } -declare_lint_pass!(Transmute => [ +pub struct Transmute { + msrv: Option<RustcVersion>, +} +impl_lint_pass!(Transmute => [ CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, TRANSMUTE_PTR_TO_PTR, @@ -401,13 +405,18 @@ declare_lint_pass!(Transmute => [ TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTE_UNDEFINED_REPR, ]); - +impl Transmute { + #[must_use] + pub fn new(msrv: Option<RustcVersion>) -> Self { + Self { msrv } + } +} impl<'tcx> LateLintPass<'tcx> for Transmute { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Call(path_expr, [arg]) = e.kind; - if let ExprKind::Path(ref qpath) = path_expr.kind; - if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); + if let ExprKind::Path(QPath::Resolved(None, path)) = path_expr.kind; + if let Some(def_id) = path.res.opt_def_id(); if cx.tcx.is_diagnostic_item(sym::transmute, def_id); then { // Avoid suggesting non-const operations in const contexts: @@ -427,7 +436,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) - | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, qpath) + | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) @@ -446,4 +455,6 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { } } } + + extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index f3653199b3758..5eb03275b8ec1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -1,11 +1,12 @@ -use super::utils::get_type_snippet; use super::TRANSMUTE_PTR_TO_REF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{meets_msrv, msrvs, sugg}; use rustc_errors::Applicability; -use rustc_hir::{Expr, Mutability, QPath}; +use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; +use rustc_semver::RustcVersion; /// Checks for `transmute_ptr_to_ref` lint. /// Returns `true` if it's triggered, otherwise returns `false`. @@ -15,7 +16,8 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, - qpath: &'tcx QPath<'_>, + path: &'tcx Path<'_>, + msrv: Option<RustcVersion>, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => { @@ -34,19 +36,34 @@ pub(super) fn check<'tcx>( } else { ("&*", "*const") }; + let mut app = Applicability::MachineApplicable; - let arg = if from_ptr_ty.ty == *to_ref_ty { - arg + let sugg = if let Some(ty) = get_explicit_type(path) { + let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); + if meets_msrv(msrv, msrvs::POINTER_CAST) { + format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), ty_snip) + } else if from_ptr_ty.has_erased_regions() { + sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, ty_snip))) + .to_string() + } else { + sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, ty_snip))).to_string() + } + } else if from_ptr_ty.ty == *to_ref_ty { + if from_ptr_ty.has_erased_regions() { + if meets_msrv(msrv, msrvs::POINTER_CAST) { + format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), to_ref_ty) + } else { + sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, to_ref_ty))) + .to_string() + } + } else { + sugg::make_unop(deref, arg).to_string() + } } else { - arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, *to_ref_ty))) + sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, to_ref_ty))).to_string() }; - diag.span_suggestion( - e.span, - "try", - sugg::make_unop(deref, arg).to_string(), - Applicability::Unspecified, - ); + diag.span_suggestion(e.span, "try", sugg, app); }, ); true @@ -54,3 +71,14 @@ pub(super) fn check<'tcx>( _ => false, } } + +/// Gets the type `Bar` in `…::transmute<Foo, &Bar>`. +fn get_explicit_type<'tcx>(path: &'tcx Path<'tcx>) -> Option<&'tcx hir::Ty<'tcx>> { + if let GenericArg::Type(ty) = path.segments.last()?.args?.args.get(1)? + && let TyKind::Rptr(_, ty) = &ty.kind + { + Some(ty.ty) + } else { + None + } +} diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index 8ea985a898431..8122cd716e011 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -4,7 +4,7 @@ use clippy_utils::sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeVisitable}; /// Checks for `useless_transmute` lint. /// Returns `true` if it's triggered, otherwise returns `false`. diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 0cbf5ccefa6d8..74927570b40eb 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,35 +1,9 @@ -use clippy_utils::last_path_segment; -use clippy_utils::source::snippet; -use if_chain::if_chain; -use rustc_hir::{Expr, GenericArg, QPath, TyKind}; +use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited}; -/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is -/// not available , use -/// the type's `ToString` implementation. In weird cases it could lead to types -/// with invalid `'_` -/// lifetime, but it should be rare. -pub(super) fn get_type_snippet(cx: &LateContext<'_>, path: &QPath<'_>, to_ref_ty: Ty<'_>) -> String { - let seg = last_path_segment(path); - if_chain! { - if let Some(params) = seg.args; - if !params.parenthesized; - if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }).nth(1); - if let TyKind::Rptr(_, ref to_ty) = to_ty.kind; - then { - return snippet(cx, to_ty.ty.span, &to_ref_ty.to_string()).to_string(); - } - } - - to_ref_ty.to_string() -} - // check if the component types of the transmuted collection and the result have different ABI, // size or alignment pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index f35f44eda5679..94945b2e1a9e2 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m return false; } - let ltopt = if lt.is_elided() { + let ltopt = if lt.name.is_anonymous() { String::new() } else { format!("{} ", lt.name.ident().as_str()) diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index c632f822544a7..b2f536ca7815b 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::TypeVisitable; use rustc_span::symbol::sym; use rustc_typeck::hir_ty_to_ty; diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index f58da7ce9b420..b0fce91abeb7d 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{get_trait_def_id, paths}; use if_chain::if_chain; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind, StmtKind}; +use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate}; @@ -116,7 +116,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> { if_chain! { - if let ExprKind::Closure { body, fn_decl_span, .. } = arg.kind; + if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind; if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind(); let ret_ty = substs.as_closure().sig().output(); let ty = cx.tcx.erase_late_bound_regions(ret_ty); 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 27678c8ba3c46..cf509455aad0a 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 @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Ty, TypeFoldable, TypeSuperFoldable, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TypeVisitable, TypeSuperVisitable, TypeVisitor}; use super::LET_UNIT_VALUE; diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs index 7d4373b2a57bc..ea5aadbbca1c6 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; +use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, subst::GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -155,7 +155,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> { if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind; if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; - if let [vec, Expr { kind: ExprKind::Closure{ body: closure_body_id, .. }, .. }] = args; + if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args; if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index c8ec4442ab1a4..a832dfcccaf36 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, YieldSource}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, IsAsync, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -68,20 +68,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { span: Span, hir_id: HirId, ) { - if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }) = &fn_kind { - if matches!(asyncness, IsAsync::Async) { - let mut visitor = AsyncFnVisitor { cx, found_await: false }; - walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id); - if !visitor.found_await { - span_lint_and_help( - cx, - UNUSED_ASYNC, - span, - "unused `async` for function with no await statements", - None, - "consider removing the `async` from this function", - ); - } + if !span.from_expansion() && fn_kind.asyncness() == IsAsync::Async { + let mut visitor = AsyncFnVisitor { cx, found_await: false }; + walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id); + if !visitor.found_await { + span_lint_and_help( + cx, + UNUSED_ASYNC, + span, + "unused `async` for function with no await statements", + None, + "consider removing the `async` from this function", + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 9b9e25326f966..d3f9e5abfd739 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{path_to_local, usage::is_potentially_mutated}; @@ -251,9 +251,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { unwrappable.kind.error_variant_pattern() }; - span_lint_and_then( + span_lint_hir_and_then( self.cx, UNNECESSARY_UNWRAP, + expr.hir_id, expr.span, &format!( "called `{}` on `{}` after checking its variant with `{}`", @@ -283,9 +284,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { }, ); } else { - span_lint_and_then( + span_lint_hir_and_then( self.cx, PANICKING_UNWRAP, + expr.hir_id, expr.span, &format!("this call to `{}()` will always panic", method_name.ident.name), diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 2c8820eb7e1a1..bbb04c9945a09 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; +use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{Ident, Symbol}; @@ -466,13 +466,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(scrutinee); self.slice(arms, |arm| self.arm(arm)); }, - ExprKind::Closure { + ExprKind::Closure(&Closure { capture_clause, fn_decl, body: body_id, movability, .. - } => { + }) => { let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}"))); let ret_ty = match fn_decl.output { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index b885e5132f1ec..a94f0357977ea 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,3 +1,4 @@ +use crate::utils::internal_lints::metadata_collector::is_deprecated_lint; use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; @@ -338,6 +339,46 @@ declare_clippy_lint! { "checking if all necessary steps were taken when adding a MSRV to a lint" } +declare_clippy_lint! { + /// ### What it does + /// Checks for cases of an auto-generated deprecated lint without an updated reason, + /// i.e. `"default deprecation note"`. + /// + /// ### Why is this bad? + /// Indicates that the documentation is incomplete. + /// + /// ### Example + /// ```rust,ignore + /// declare_deprecated_lint! { + /// /// ### What it does + /// /// Nothing. This lint has been deprecated. + /// /// + /// /// ### Deprecation reason + /// /// TODO + /// #[clippy::version = "1.63.0"] + /// pub COOL_LINT, + /// "default deprecation note" + /// } + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// declare_deprecated_lint! { + /// /// ### What it does + /// /// Nothing. This lint has been deprecated. + /// /// + /// /// ### Deprecation reason + /// /// This lint has been replaced by `cooler_lint` + /// #[clippy::version = "1.63.0"] + /// pub COOL_LINT, + /// "this lint has been replaced by `cooler_lint`" + /// } + /// ``` + pub DEFAULT_DEPRECATION_REASON, + internal, + "found 'default deprecation note' in a deprecated lint declaration" +} + declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { @@ -375,42 +416,67 @@ pub struct LintWithoutLintPass { registered_lints: FxHashSet<Symbol>, } -impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]); +impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]); impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) { + if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) + || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id()) + { return; } if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind { - if is_lint_ref_type(cx, ty) { + let is_lint_ref_ty = is_lint_ref_type(cx, ty); + if is_deprecated_lint(cx, ty) || is_lint_ref_ty { check_invalid_clippy_version_attribute(cx, item); let expr = &cx.tcx.hir().body(body_id).value; - if_chain! { - if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind; - if let ExprKind::Struct(_, fields, _) = inner_exp.kind; - let field = fields - .iter() - .find(|f| f.ident.as_str() == "desc") - .expect("lints must have a description field"); - if let ExprKind::Lit(Spanned { - node: LitKind::Str(ref sym, _), - .. - }) = field.expr.kind; - if sym.as_str() == "default lint description"; - - then { + let fields; + if is_lint_ref_ty { + if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind + && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind { + fields = struct_fields; + } else { + return; + } + } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind { + fields = struct_fields; + } else { + return; + } + + let field = fields + .iter() + .find(|f| f.ident.as_str() == "desc") + .expect("lints must have a description field"); + + if let ExprKind::Lit(Spanned { + node: LitKind::Str(ref sym, _), + .. + }) = field.expr.kind + { + let sym_str = sym.as_str(); + if is_lint_ref_ty { + if sym_str == "default lint description" { + span_lint( + cx, + DEFAULT_LINT, + item.span, + &format!("the lint `{}` has the default lint description", item.ident.name), + ); + } + + self.declared_lints.insert(item.ident.name, item.span); + } else if sym_str == "default deprecation note" { span_lint( cx, - DEFAULT_LINT, + DEFAULT_DEPRECATION_REASON, item.span, - &format!("the lint `{}` has the default lint description", item.ident.name), + &format!("the lint `{}` has the default deprecation reason", item.ident.name), ); } } - self.declared_lints.insert(item.ident.name, item.span); } } else if let Some(macro_call) = root_macro_call_first_node(cx, item) { if !matches!( @@ -668,6 +734,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { let body = cx.tcx.hir().body(*body); let only_expr = peel_blocks_with_stmt(&body.value); if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind; + if let ExprKind::Path(..) = span_call_args[0].kind; then { let and_then_snippets = get_and_then_snippets(cx, and_then_args); let mut sle = SpanlessEq::new(cx).deny_side_effects(); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 99e9e3275ab53..6518e0a6ea073 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -104,7 +104,7 @@ macro_rules! RENAME_VALUE_TEMPLATE { }; } -const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [ +const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ &["clippy_utils", "diagnostics", "span_lint"], &["clippy_utils", "diagnostics", "span_lint_and_help"], &["clippy_utils", "diagnostics", "span_lint_and_note"], @@ -112,7 +112,6 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [ &["clippy_utils", "diagnostics", "span_lint_and_sugg"], &["clippy_utils", "diagnostics", "span_lint_and_then"], &["clippy_utils", "diagnostics", "span_lint_hir_and_then"], - &["clippy_utils", "diagnostics", "span_lint_and_sugg_for_edges"], ]; const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [ ("span_suggestion", false), @@ -191,7 +190,12 @@ impl MetadataCollector { lints: BinaryHeap::<LintMetadata>::default(), applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), config: collect_configs(), - clippy_project_root: clippy_dev::clippy_project_root(), + clippy_project_root: std::env::current_dir() + .expect("failed to get current dir") + .ancestors() + .nth(1) + .expect("failed to get project root") + .to_path_buf(), } } @@ -842,7 +846,7 @@ fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> { .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level)) } -fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { +pub(super) fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { if let hir::TyKind::Path(ref path) = ty.kind { if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) { return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE); diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs index 4d86abd0fa123..0fee3e812d286 100644 --- a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs +++ b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs @@ -20,6 +20,11 @@ declare_clippy_lint! { /// ```rust /// vec!(1, 2, 3, 4, 5).resize(0, 5) /// ``` + /// + /// Use instead: + /// ```rust + /// vec!(1, 2, 3, 4, 5).clear() + /// ``` #[clippy::version = "1.46.0"] pub VEC_RESIZE_TO_ZERO, correctness, diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 70b0560e67604..8dc43c0e29436 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_hir::{self as hir, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{Adt, Ty, TypeFoldable}; +use rustc_middle::ty::{Adt, Ty, TypeVisitable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use rustc_typeck::hir_ty_to_ty; diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index c4e0b8448ab3f..bb443bdc1168f 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.63" +version = "0.1.64" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 6487199172e09..431b09d53c33b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -168,8 +168,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv), (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp), (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm), - (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => { - lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb) + (Closure(lb, lc, la, lm, lf, le, _), Closure(rb, rc, ra, rm, rf, re, _)) => { + eq_closure_binder(lb, rb) && lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(le, re) }, (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb), (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), @@ -561,6 +561,15 @@ pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool { }) } +pub fn eq_closure_binder(l: &ClosureBinder, r: &ClosureBinder) -> bool { + match (l, r) { + (ClosureBinder::NotPresent, ClosureBinder::NotPresent) => true, + (ClosureBinder::For { generic_params: lp, .. }, ClosureBinder::For { generic_params: rp, .. }) => + lp.len() == rp.len() && std::iter::zip(lp.iter(), rp.iter()).all(|(l, r)| eq_generic_param(l, r)), + _ => false, + } +} + pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool { match (l, r) { (FnRetTy::Default(_), FnRetTy::Default(_)) => true, @@ -600,8 +609,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { pub fn eq_ext(l: &Extern, r: &Extern) -> bool { use Extern::*; match (l, r) { - (None, None) | (Implicit, Implicit) => true, - (Explicit(l), Explicit(r)) => eq_str_lit(l, r), + (None, None) | (Implicit(_), Implicit(_)) => true, + (Explicit(l,_), Explicit(r,_)) => eq_str_lit(l, r), _ => false, } } diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 39595f589c70b..7f55db3b31f70 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,7 +8,7 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::source_map::Span; @@ -219,95 +219,6 @@ pub fn span_lint_and_sugg<'a, T: LintContext>( }); } -/// Like [`span_lint_and_sugg`] with a focus on the edges. The output will either -/// emit single span or multispan suggestion depending on the number of its lines. -/// -/// If the given suggestion string has more lines than the maximum display length defined by -/// [`MAX_SUGGESTION_HIGHLIGHT_LINES`][`rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES`], -/// this function will split the suggestion and span to showcase the change for the top and -/// bottom edge of the code. For normal suggestions, in one display window, the help message -/// will be combined with a colon. -/// -/// Multipart suggestions like the one being created here currently cannot be -/// applied by rustfix (See [rustfix#141](https://github.com/rust-lang/rustfix/issues/141)). -/// Testing rustfix with this lint emission function might require a file with -/// suggestions that can be fixed and those that can't. See -/// [clippy#8520](https://github.com/rust-lang/rust-clippy/pull/8520/files) for -/// an example and of this. -/// -/// # Example for a long suggestion -/// -/// ```text -/// error: called `map(..).flatten()` on `Option` -/// --> $DIR/map_flatten.rs:8:10 -/// | -/// LL | .map(|x| { -/// | __________^ -/// LL | | if x <= 5 { -/// LL | | Some(x) -/// LL | | } else { -/// ... | -/// LL | | }) -/// LL | | .flatten(); -/// | |__________________^ -/// | -/// = note: `-D clippy::map-flatten` implied by `-D warnings` -/// help: try replacing `map` with `and_then` -/// | -/// LL ~ .and_then(|x| { -/// LL + if x <= 5 { -/// LL + Some(x) -/// | -/// help: and remove the `.flatten()` -/// | -/// LL + None -/// LL + } -/// LL ~ }); -/// | -/// ``` -pub fn span_lint_and_sugg_for_edges( - cx: &LateContext<'_>, - lint: &'static Lint, - sp: Span, - msg: &str, - helps: &[&str; 2], - sugg: String, - applicability: Applicability, -) { - span_lint_and_then(cx, lint, sp, msg, |diag| { - let sugg_lines_count = sugg.lines().count(); - if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES { - let sm = cx.sess().source_map(); - if let (Ok(line_upper), Ok(line_bottom)) = - (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi())) - { - let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2; - let span_upper = sm.span_until_char( - sp.with_hi(line_upper.sf.lines(|lines| lines[line_upper.line + split_idx])), - '\n', - ); - let span_bottom = sp.with_lo(line_bottom.sf.lines(|lines| lines[line_bottom.line - split_idx])); - - let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>(); - let sugg_upper = sugg_lines_vec[..split_idx].join("\n"); - let sugg_bottom = sugg_lines_vec[sugg_lines_count - split_idx..].join("\n"); - - diag.span_suggestion(span_upper, helps[0], sugg_upper, applicability); - diag.span_suggestion(span_bottom, helps[1], sugg_bottom, applicability); - - return; - } - } - diag.span_suggestion_with_style( - sp, - &helps.join(", "), - sugg, - applicability, - rustc_errors::SuggestionStyle::ShowAlways, - ); - }); -} - /// Create a suggestion made from several `span → replacement`. /// /// Note: in the JSON format (used by `compiletest_rs`), the help message will diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index af62c4afd5a51..1a8e8c996316f 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,20 +1,25 @@ use crate::consts::constant_simple; +use crate::macros::macro_backtrace; use crate::source::snippet_opt; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::HirIdMap; use rustc_hir::{ - ArrayLen, BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId, + ArrayLen, BinOpKind, Closure, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; use std::hash::{Hash, Hasher}; +/// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but +/// other conditions would make them equal. +type SpanlessEqCallback<'a> = dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a; + /// Type used to check whether two ast are the same. This is different from the /// operator `==` on ast types as this operator would compare true equality with /// ID and span. @@ -25,7 +30,7 @@ pub struct SpanlessEq<'a, 'tcx> { cx: &'a LateContext<'tcx>, maybe_typeck_results: Option<(&'tcx TypeckResults<'tcx>, &'tcx TypeckResults<'tcx>)>, allow_side_effects: bool, - expr_fallback: Option<Box<dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a>>, + expr_fallback: Option<Box<SpanlessEqCallback<'a>>>, } impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { @@ -97,7 +102,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { impl HirEqInterExpr<'_, '_, '_> { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { match (&left.kind, &right.kind) { - (&StmtKind::Local(l), &StmtKind::Local(r)) => { + (&StmtKind::Local(l, ), &StmtKind::Local(r, )) => { // This additional check ensures that the type of the locals are equivalent even if the init // expression or type have some inferred parts. if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results { @@ -112,6 +117,7 @@ impl HirEqInterExpr<'_, '_, '_> { // these only get added if the init and type is equal. both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) + && both(&l.els, &r.els, |l, r| self.eq_block(l, r)) && self.eq_pat(l.pat, r.pat) }, (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r), @@ -121,6 +127,9 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two blocks are the same. fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { + if self.cannot_be_compared_block(left) || self.cannot_be_compared_block(right) { + return false; + } match (left.stmts, left.expr, right.stmts, right.expr) { ([], None, [], None) => { // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro @@ -171,6 +180,38 @@ impl HirEqInterExpr<'_, '_, '_> { } } + fn cannot_be_compared_block(&mut self, block: &Block<'_>) -> bool { + if block.stmts.last().map_or(false, |stmt| { + matches!( + stmt.kind, + StmtKind::Semi(semi_expr) if self.should_ignore(semi_expr) + ) + }) { + return true; + } + + if let Some(block_expr) = block.expr + && self.should_ignore(block_expr) + { + return true + } + + false + } + + fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { + if macro_backtrace(expr.span).last().map_or(false, |macro_call| { + matches!( + &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), + Some(sym::todo_macro | sym::unimplemented_macro) + ) + }) { + return true; + } + + false + } + pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool { match (left, right) { (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true, @@ -622,9 +663,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(e); self.hash_ty(ty); }, - ExprKind::Closure { + ExprKind::Closure(&Closure { capture_clause, body, .. - } => { + }) => { std::mem::discriminant(&capture_clause).hash(&mut self.s); // closures inherit TypeckResults self.hash_expr(&self.cx.tcx.hir().body(body).value); @@ -881,11 +922,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&b.kind).hash(&mut self.s); match &b.kind { - StmtKind::Local(local) => { + StmtKind::Local(local, ) => { self.hash_pat(local.pat); if let Some(init) = local.init { self.hash_expr(init); } + if let Some(els) = local.els { + self.hash_block(els); + } }, StmtKind::Item(..) => {}, StmtKind::Expr(expr) | StmtKind::Semi(expr) => { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 5106c39b5c6fc..0089e1b64006f 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,7 +1,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_else)] -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(lint_reasons)] #![feature(once_cell)] #![feature(rustc_private)] @@ -79,10 +79,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ - def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl, - HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, - Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, - UnOp, + def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, Expr, + ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, + Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, + TraitRef, TyKind, UnOp, }; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; @@ -93,7 +93,7 @@ use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{ ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType, PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType, }; -use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture}; +use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture}; use rustc_middle::ty::{FloatTy, IntTy, UintTy}; use rustc_semver::RustcVersion; use rustc_session::Session; @@ -183,7 +183,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { let hir = cx.tcx.hir(); if_chain! { - if let Some(Node::Binding(pat)) = hir.find(hir_id); + if let Some(Node::Pat(pat)) = hir.find(hir_id); if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..)); let parent = hir.get_parent_node(hir_id); if let Some(Node::Local(local)) = hir.find(parent); @@ -1539,9 +1539,13 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc None } -/// Returns `true` if the lint is allowed in the current context +/// Returns `true` if the lint is allowed in the current context. This is useful for +/// skipping long running code when it's unnecessary /// -/// Useful for skipping long running code when it's unnecessary +/// This function should check the lint level for the same node, that the lint will +/// be emitted at. If the information is buffered to be emitted at a later point, please +/// make sure to use `span_lint_hir` functions to emit the lint. This ensures that +/// expectations at the checked nodes will be fulfilled. pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool { cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow } @@ -1695,7 +1699,7 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t _, &[ Expr { - kind: ExprKind::Closure { body, .. }, + kind: ExprKind::Closure(&Closure { body, .. }), .. }, ], @@ -1782,7 +1786,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool } match expr.kind { - ExprKind::Closure { body, .. } => is_body_identity_function(cx, cx.tcx.hir().body(body)), + ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), } } @@ -2058,6 +2062,21 @@ pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { (e, count) } +/// Peels off all references on the type. Returns the underlying type and the number of references +/// removed. +pub fn peel_hir_ty_refs<'a>(mut ty: &'a hir::Ty<'a>) -> (&'a hir::Ty<'a>, usize) { + let mut count = 0; + loop { + match &ty.kind { + TyKind::Rptr(_, ref_ty) => { + ty = ref_ty.ty; + count += 1; + }, + _ => break (ty, count), + } + } +} + /// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is /// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { @@ -2110,7 +2129,7 @@ fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn( } } names.sort_unstable(); - f(&*entry.insert(names)) + f(entry.insert(names)) }, } } @@ -2168,6 +2187,50 @@ pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") } +/// Walks the HIR tree from the given expression, up to the node where the value produced by the +/// expression is consumed. Calls the function for every node encountered this way until it returns +/// `Some`. +/// +/// This allows walking through `if`, `match`, `break`, block expressions to find where the value +/// produced by the expression is consumed. +pub fn walk_to_expr_usage<'tcx, T>( + cx: &LateContext<'tcx>, + e: &Expr<'tcx>, + mut f: impl FnMut(Node<'tcx>, HirId) -> Option<T>, +) -> Option<T> { + let map = cx.tcx.hir(); + let mut iter = map.parent_iter(e.hir_id); + let mut child_id = e.hir_id; + + while let Some((parent_id, parent)) = iter.next() { + if let Some(x) = f(parent, child_id) { + return Some(x); + } + let parent = match parent { + Node::Expr(e) => e, + Node::Block(Block { expr: Some(body), .. }) | Node::Arm(Arm { body, .. }) if body.hir_id == child_id => { + child_id = parent_id; + continue; + }, + Node::Arm(a) if a.body.hir_id == child_id => { + child_id = parent_id; + continue; + }, + _ => return None, + }; + match parent.kind { + ExprKind::If(child, ..) | ExprKind::Match(child, ..) if child.hir_id != child_id => child_id = parent_id, + ExprKind::Break(Destination { target_id: Ok(id), .. }, _) => { + child_id = id; + iter = map.parent_iter(id); + }, + ExprKind::Block(..) => child_id = parent_id, + _ => return None, + } + } + None +} + macro_rules! op_utils { ($($name:ident $assign:ident)*) => { /// Binary operation traits like `LangItem::Add` diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index b9ec2c19fdd31..b09c929f76e22 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -12,8 +12,8 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,53,0 { OR_PATTERNS, MANUAL_BITS } - 1,52,0 { STR_SPLIT_ONCE } + 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN } + 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } 1,50,0 { BOOL_THEN } 1,47,0 { TAU } @@ -23,14 +23,15 @@ msrv_aliases! { 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS } 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } - 1,38,0 { POINTER_CAST } + 1,38,0 { POINTER_CAST, REM_EUCLID } 1,37,0 { TYPE_ALIAS_ENUM_VARIANTS } 1,36,0 { ITERATOR_COPIED } 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,28,0 { FROM_BOOL } - 1,26,0 { RANGE_INCLUSIVE } + 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } + 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } 1,24,0 { IS_ASCII_DIGIT } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 89789c3d85135..6542e77113b45 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -21,8 +21,14 @@ pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"]; pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"]; +pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; +pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"]; +pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; +pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; +pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; +pub const CORE_ITER_INTO_ITER: [&str; 6] = ["core", "iter", "traits", "collect", "IntoIterator", "into_iter"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; @@ -50,6 +56,7 @@ pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWri pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"]; pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"]; +pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"]; #[cfg(feature = "internal")] pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; #[cfg(feature = "internal")] @@ -62,6 +69,7 @@ pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; +pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; @@ -83,8 +91,6 @@ pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"]; pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; -pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"]; -pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"]; 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"]; @@ -144,6 +150,7 @@ pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_p pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_GET: [&str; 4] = ["core", "slice", "<impl [T]>", "get"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"]; +pub const SLICE_INTO: [&str; 4] = ["core", "slice", "<impl [T]>", "iter"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; @@ -153,6 +160,7 @@ pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_s pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; pub const STR_BYTES: [&str; 4] = ["core", "str", "<impl str>", "bytes"]; +pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"]; pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"]; @@ -178,6 +186,7 @@ pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_wri pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; +pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; 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 498dcbb89006d..9690ad2777177 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 @@ -124,6 +124,7 @@ fn check_rvalue<'tcx>( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { check_place(tcx, *place, span, body) }, + Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) | Rvalue::Cast( @@ -251,6 +252,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B } }, ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref @@ -353,7 +355,7 @@ fn check_terminator<'a, 'tcx>( fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool { tcx.is_const_fn(def_id) && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { - if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level { + if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index aa119539b1b39..4326a103d44b7 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -8,7 +8,7 @@ use rustc_ast::{ast, token}; use rustc_ast_pretty::pprust::token_kind_to_string; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{ExprKind, HirId, MutTy, TyKind}; +use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::hir::place::ProjectionKind; @@ -790,7 +790,7 @@ pub struct DerefClosure { /// /// note: this only works on single line immutable closures with exactly one input parameter. pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> { - if let hir::ExprKind::Closure { fn_decl, body, .. } = closure.kind { + if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind { let closure_body = cx.tcx.hir().body(body); // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`) // a type annotation is present if param `kind` is different from `TyKind::Infer` diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 227e97d37ecc3..a426fa1b0ffcf 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -2,19 +2,20 @@ #![allow(clippy::module_name_repetitions)] +use core::ops::ControlFlow; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, LangItem, TyKind, Unsafety}; +use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, - VariantDiscr, + self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy, + Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -501,16 +502,46 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P #[derive(Clone, Copy)] pub enum ExprFnSig<'tcx> { Sig(Binder<'tcx, FnSig<'tcx>>), - Closure(Binder<'tcx, FnSig<'tcx>>), + Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>), Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>), } impl<'tcx> ExprFnSig<'tcx> { - /// Gets the argument type at the given offset. - pub fn input(self, i: usize) -> Binder<'tcx, Ty<'tcx>> { + /// Gets the argument type at the given offset. This will return `None` when the index is out of + /// bounds only for variadic functions, otherwise this will panic. + pub fn input(self, i: usize) -> Option<Binder<'tcx, Ty<'tcx>>> { match self { - Self::Sig(sig) => sig.input(i), - Self::Closure(sig) => sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), - Self::Trait(inputs, _) => inputs.map_bound(|ty| ty.tuple_fields()[i]), + Self::Sig(sig) => { + if sig.c_variadic() { + sig.inputs().map_bound(|inputs| inputs.get(i).copied()).transpose() + } else { + Some(sig.input(i)) + } + }, + Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), + Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), + } + } + + /// Gets the argument type at the given offset. For closures this will also get the type as + /// written. This will return `None` when the index is out of bounds only for variadic + /// functions, otherwise this will panic. + pub fn input_with_hir(self, i: usize) -> Option<(Option<&'tcx hir::Ty<'tcx>>, Binder<'tcx, Ty<'tcx>>)> { + match self { + Self::Sig(sig) => { + if sig.c_variadic() { + sig.inputs() + .map_bound(|inputs| inputs.get(i).copied()) + .transpose() + .map(|arg| (None, arg)) + } else { + Some((None, sig.input(i))) + } + }, + Self::Closure(decl, sig) => Some(( + decl.and_then(|decl| decl.inputs.get(i)), + sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), + )), + Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), } } @@ -518,7 +549,7 @@ impl<'tcx> ExprFnSig<'tcx> { /// specified. pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> { match self { - Self::Sig(sig) | Self::Closure(sig) => Some(sig.output()), + Self::Sig(sig) | Self::Closure(_, sig) => Some(sig.output()), Self::Trait(_, output) => output, } } @@ -529,74 +560,123 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id))) } else { - let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs(); - match *ty.kind() { - ty::Closure(_, subs) => Some(ExprFnSig::Closure(subs.as_closure().sig())), - ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs))), - ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)), - ty::Dynamic(bounds, _) => { - let lang_items = cx.tcx.lang_items(); - match bounds.principal() { - Some(bound) - if Some(bound.def_id()) == lang_items.fn_trait() - || Some(bound.def_id()) == lang_items.fn_once_trait() - || Some(bound.def_id()) == lang_items.fn_mut_trait() => - { - let output = bounds - .projection_bounds() - .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) - .map(|p| p.map_bound(|p| p.term.ty().expect("return type was a const"))); - Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output)) - }, - _ => None, + ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs()) + } +} + +fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> { + match *ty.kind() { + ty::Closure(id, subs) => { + let decl = id + .as_local() + .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); + Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) + }, + ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs))), + ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)), + ty::Dynamic(bounds, _) => { + let lang_items = cx.tcx.lang_items(); + match bounds.principal() { + Some(bound) + if Some(bound.def_id()) == lang_items.fn_trait() + || Some(bound.def_id()) == lang_items.fn_once_trait() + || Some(bound.def_id()) == lang_items.fn_mut_trait() => + { + let output = bounds + .projection_bounds() + .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) + .map(|p| p.map_bound(|p| p.term.ty().unwrap())); + Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output)) + }, + _ => None, + } + }, + ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { + Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), + _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)), + }, + ty::Param(_) => sig_from_bounds(cx, ty), + _ => None, + } +} + +fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> { + let mut inputs = None; + let mut output = None; + let lang_items = cx.tcx.lang_items(); + + for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) { + match pred.kind().skip_binder() { + PredicateKind::Trait(p) + if (lang_items.fn_trait() == Some(p.def_id()) + || lang_items.fn_mut_trait() == Some(p.def_id()) + || lang_items.fn_once_trait() == Some(p.def_id())) + && p.self_ty() == ty => + { + if inputs.is_some() { + // Multiple different fn trait impls. Is this even allowed? + return None; } + inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1))); }, - ty::Param(_) | ty::Projection(..) => { - let mut inputs = None; - let mut output = None; - let lang_items = cx.tcx.lang_items(); - - for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) { - let mut is_input = false; - if let Some(ty) = pred - .kind() - .map_bound(|pred| match pred { - PredicateKind::Trait(p) - if (lang_items.fn_trait() == Some(p.def_id()) - || lang_items.fn_mut_trait() == Some(p.def_id()) - || lang_items.fn_once_trait() == Some(p.def_id())) - && p.self_ty() == ty => - { - is_input = true; - Some(p.trait_ref.substs.type_at(1)) - }, - PredicateKind::Projection(p) - if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() - && p.projection_ty.self_ty() == ty => - { - is_input = false; - p.term.ty() - }, - _ => None, - }) - .transpose() - { - if is_input && inputs.is_none() { - inputs = Some(ty); - } else if !is_input && output.is_none() { - output = Some(ty); - } else { - // Multiple different fn trait impls. Is this even allowed? - return None; - } - } + PredicateKind::Projection(p) + if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() + && p.projection_ty.self_ty() == ty => + { + if output.is_some() { + // Multiple different fn trait impls. Is this even allowed? + return None; } + output = Some(pred.kind().rebind(p.term.ty().unwrap())); + }, + _ => (), + } + } + + inputs.map(|ty| ExprFnSig::Trait(ty, output)) +} + +fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> { + let mut inputs = None; + let mut output = None; + let lang_items = cx.tcx.lang_items(); - inputs.map(|ty| ExprFnSig::Trait(ty, output)) + for pred in cx + .tcx + .bound_explicit_item_bounds(ty.item_def_id) + .transpose_iter() + .map(|x| x.map_bound(|(p, _)| p)) + { + match pred.0.kind().skip_binder() { + PredicateKind::Trait(p) + if (lang_items.fn_trait() == Some(p.def_id()) + || lang_items.fn_mut_trait() == Some(p.def_id()) + || lang_items.fn_once_trait() == Some(p.def_id())) => + { + if inputs.is_some() { + // Multiple different fn trait impls. Is this even allowed? + return None; + } + inputs = Some( + pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) + .subst(cx.tcx, ty.substs), + ); }, - _ => None, + PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { + if output.is_some() { + // Multiple different fn trait impls. Is this even allowed? + return None; + } + output = Some( + pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap())) + .subst(cx.tcx, ty.substs), + ); + }, + _ => (), } } + + inputs.map(|ty| ExprFnSig::Trait(ty, output)) } #[derive(Clone, Copy)] @@ -667,3 +747,45 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { false } } + +pub fn for_each_top_level_late_bound_region<B>( + ty: Ty<'_>, + f: impl FnMut(BoundRegion) -> ControlFlow<B>, +) -> ControlFlow<B> { + struct V<F> { + index: u32, + f: F, + } + impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<'tcx> for V<F> { + type BreakTy = B; + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { + if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index { + (self.f)(bound) + } else { + ControlFlow::Continue(()) + } + } + fn visit_binder<T: TypeVisitable<'tcx>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> { + self.index += 1; + let res = t.super_visit_with(self); + self.index -= 1; + res + } + } + ty.visit_with(&mut V { index: 0, f }) +} + +/// Gets the struct or enum variant from the given `Res` +pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> { + match res { + Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()), + Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)), + Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()), + Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => { + let var_id = cx.tcx.parent(id); + Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id)) + }, + Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()), + _ => None, + } +} diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index b6c8f1d516e55..68cfa8c1aa8ec 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -1,16 +1,18 @@ +use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; use rustc_hir::{ - Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Stmt, UnOp, UnsafeSource, - Unsafety, + Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, QPath, Stmt, UnOp, + UnsafeSource, Unsafety, }; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; -use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; +use rustc_middle::ty::{self, Ty, TypeckResults}; /// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested /// bodies (i.e. closures) are visited. @@ -494,3 +496,124 @@ pub fn for_each_local_use_after_expr<'tcx, B>( ControlFlow::Continue(()) } } + +// Calls the given function for every unconsumed temporary created by the expression. Note the +// function is only guaranteed to be called for types which need to be dropped, but it may be called +// for other types. +pub fn for_each_unconsumed_temporary<'tcx, B>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'tcx>, + mut f: impl FnMut(Ty<'tcx>) -> ControlFlow<B>, +) -> ControlFlow<B> { + // Todo: Handle partially consumed values. + fn helper<'tcx, B>( + typeck: &'tcx TypeckResults<'tcx>, + consume: bool, + e: &'tcx Expr<'tcx>, + f: &mut impl FnMut(Ty<'tcx>) -> ControlFlow<B>, + ) -> ControlFlow<B> { + if !consume + || matches!( + typeck.expr_adjustments(e), + [adjust, ..] if matches!(adjust.kind, Adjust::Borrow(_) | Adjust::Deref(_)) + ) + { + match e.kind { + ExprKind::Path(QPath::Resolved(None, p)) + if matches!(p.res, Res::Def(DefKind::Ctor(_, CtorKind::Const), _)) => + { + f(typeck.expr_ty(e))?; + }, + ExprKind::Path(_) + | ExprKind::Unary(UnOp::Deref, _) + | ExprKind::Index(..) + | ExprKind::Field(..) + | ExprKind::AddrOf(..) => (), + _ => f(typeck.expr_ty(e))?, + } + } + match e.kind { + ExprKind::AddrOf(_, _, e) + | ExprKind::Field(e, _) + | ExprKind::Unary(UnOp::Deref, e) + | ExprKind::Match(e, ..) + | 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) => { + helper(typeck, true, e, f)?; + }, + ExprKind::Call(callee, args) => { + helper(typeck, true, callee, f)?; + for arg in args { + helper(typeck, true, arg, f)?; + } + }, + ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => { + for arg in args { + helper(typeck, true, arg, f)?; + } + }, + ExprKind::Index(borrowed, consumed) + | ExprKind::Assign(borrowed, consumed, _) + | ExprKind::AssignOp(_, borrowed, consumed) => { + helper(typeck, false, borrowed, f)?; + helper(typeck, true, consumed, f)?; + }, + ExprKind::Binary(_, lhs, rhs) => { + helper(typeck, true, lhs, f)?; + helper(typeck, true, rhs, f)?; + }, + ExprKind::Struct(_, fields, default) => { + for field in fields { + helper(typeck, true, field.expr, f)?; + } + if let Some(default) = default { + helper(typeck, false, default, f)?; + } + }, + ExprKind::If(cond, then, else_expr) => { + helper(typeck, true, cond, f)?; + helper(typeck, true, then, f)?; + if let Some(else_expr) = else_expr { + helper(typeck, true, else_expr, f)?; + } + }, + ExprKind::Type(e, _) => { + helper(typeck, consume, e, f)?; + }, + + // Either drops temporaries, jumps out of the current expression, or has no sub expression. + ExprKind::DropTemps(_) + | ExprKind::Ret(_) + | ExprKind::Break(..) + | ExprKind::Yield(..) + | ExprKind::Block(..) + | ExprKind::Loop(..) + | ExprKind::Repeat(..) + | ExprKind::Lit(_) + | ExprKind::ConstBlock(_) + | ExprKind::Closure { .. } + | ExprKind::Path(_) + | ExprKind::Continue(_) + | ExprKind::InlineAsm(_) + | ExprKind::Err => (), + } + ControlFlow::Continue(()) + } + helper(cx.typeck_results(), true, e, &mut f) +} + +pub fn any_temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { + for_each_unconsumed_temporary(cx, e, |ty| { + if needs_ordered_drop(cx, ty) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_break() +} diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 6ad56aacf8c95..6cc6d5036b379 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-06-16" +channel = "nightly-2022-06-30" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 67467f89b475f..c219c7de830ef 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -60,6 +60,7 @@ fn test_arg_value() { assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None); assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None); assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123")); + assert_eq!(arg_value(args, "--foobar", |p| p.contains("12")), Some("123")); assert_eq!(arg_value(args, "--foo", |_| true), None); } @@ -116,7 +117,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // run on the unoptimized MIR. On the other hand this results in some false negatives. If // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. - config.opts.debugging_opts.mir_opt_level = Some(0); + config.opts.unstable_opts.mir_opt_level = Some(0); } } @@ -152,7 +153,8 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -static ICE_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = LazyLock::new(|| { +type PanicCallback = dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static; +static ICE_HOOK: LazyLock<Box<PanicCallback>> = LazyLock::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); hook @@ -334,15 +336,13 @@ pub fn main() { // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN // - IF `--no-deps` is not set (`!no_deps`) OR // - IF `--no-deps` is set and Clippy is run on the specified primary package - let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some(); + let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some() + && arg_value(&orig_args, "--force-warn", |val| val.contains("clippy::")).is_none(); let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok(); let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package); if clippy_enabled { args.extend(clippy_args); - } - - if clippy_enabled { rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run() } else { rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run() diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 061cda7e01e5b..bf7a39edf4c91 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -23,6 +23,7 @@ const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); /// All crates used in UI tests are listed here static TEST_DEPENDENCIES: &[&str] = &[ + "clippy_lints", "clippy_utils", "derive_new", "futures", @@ -41,6 +42,8 @@ static TEST_DEPENDENCIES: &[&str] = &[ // Test dependencies may need an `extern crate` here to ensure that they show up // in the depinfo file (otherwise cargo thinks they are unused) #[allow(unused_extern_crates)] +extern crate clippy_lints; +#[allow(unused_extern_crates)] extern crate clippy_utils; #[allow(unused_extern_crates)] extern crate derive_new; @@ -124,7 +127,7 @@ fn base_config(test_dir: &str) -> compiletest::Config { let mut config = compiletest::Config { edition: Some("2021".into()), mode: TestMode::Ui, - ..compiletest::Config::default() + ..Default::default() }; if let Ok(filters) = env::var("TESTNAME") { @@ -280,6 +283,24 @@ fn run_ui_cargo() { } env::set_current_dir(&src_path)?; + + let cargo_toml_path = case.path().join("Cargo.toml"); + let cargo_content = fs::read(&cargo_toml_path)?; + let cargo_parsed: toml::Value = toml::from_str( + std::str::from_utf8(&cargo_content).expect("`Cargo.toml` is not a valid utf-8 file!"), + ) + .expect("Can't parse `Cargo.toml`"); + + let _g = VarGuard::set("CARGO_MANIFEST_DIR", case.path()); + let _h = VarGuard::set( + "CARGO_PKG_RUST_VERSION", + cargo_parsed + .get("package") + .and_then(|p| p.get("rust-version")) + .and_then(toml::Value::as_str) + .unwrap_or(""), + ); + for file in fs::read_dir(&src_path)? { let file = file?; if file.file_type()?.is_dir() { diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml new file mode 100644 index 0000000000000..73ec29c5803bd --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-both-diff" +version = "0.1.0" +rust-version = "1.56" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/clippy.toml new file mode 100644 index 0000000000000..abe19b3a00710 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/clippy.toml @@ -0,0 +1 @@ +msrv = "1.59" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr new file mode 100644 index 0000000000000..9a7d802dc6d3a --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr @@ -0,0 +1,16 @@ +warning: the MSRV in `clippy.toml` and `Cargo.toml` differ; using `1.59.0` from `clippy.toml` + +error: unnecessary structure name repetition + --> $DIR/main.rs:6:21 + | +LL | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> $DIR/main.rs:1:9 + | +LL | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml new file mode 100644 index 0000000000000..2d6d547e4fe3a --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-both-same" +version = "0.1.0" +rust-version = "1.57.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/clippy.toml new file mode 100644 index 0000000000000..5cccb362c1421 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/clippy.toml @@ -0,0 +1 @@ +msrv = "1.57" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.stderr new file mode 100644 index 0000000000000..a280e1bacdfdc --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.stderr @@ -0,0 +1,14 @@ +error: unnecessary structure name repetition + --> $DIR/main.rs:6:21 + | +LL | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> $DIR/main.rs:1:9 + | +LL | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml new file mode 100644 index 0000000000000..36a53bd829d9e --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-cargo" +version = "0.1.0" +rust-version = "1.56.1" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr new file mode 100644 index 0000000000000..a280e1bacdfdc --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr @@ -0,0 +1,14 @@ +error: unnecessary structure name repetition + --> $DIR/main.rs:6:21 + | +LL | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> $DIR/main.rs:1:9 + | +LL | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml new file mode 100644 index 0000000000000..9f644a1a39a50 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "fail-clippy" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/clippy.toml new file mode 100644 index 0000000000000..ddbdbc1fa2590 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/clippy.toml @@ -0,0 +1 @@ +msrv = "1.58" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr new file mode 100644 index 0000000000000..a280e1bacdfdc --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr @@ -0,0 +1,14 @@ +error: unnecessary structure name repetition + --> $DIR/main.rs:6:21 + | +LL | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> $DIR/main.rs:1:9 + | +LL | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml new file mode 100644 index 0000000000000..5380e993b2936 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-file-attr" +version = "0.1.0" +rust-version = "1.13" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/clippy.toml new file mode 100644 index 0000000000000..ea5d806594b5e --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/clippy.toml @@ -0,0 +1 @@ +msrv = "1.13.0" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.rs new file mode 100644 index 0000000000000..bcbffa82a5417 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.rs @@ -0,0 +1,16 @@ +// FIXME: this should produce a warning, because the attribute says 1.58 and the cargo.toml file +// says 1.13 + +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.58.0"] +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr new file mode 100644 index 0000000000000..88f6e00922bc4 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr @@ -0,0 +1,14 @@ +error: unnecessary structure name repetition + --> $DIR/main.rs:11:21 + | +LL | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> $DIR/main.rs:6:9 + | +LL | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml new file mode 100644 index 0000000000000..1f9bd8f9a84e3 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-both-same" +version = "0.1.0" +rust-version = "1.13.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/clippy.toml new file mode 100644 index 0000000000000..5e8e48b636b63 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/clippy.toml @@ -0,0 +1 @@ +msrv = "1.13" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_both_same/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml new file mode 100644 index 0000000000000..77538027c0f87 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-cargo" +version = "0.1.0" +rust-version = "1.13.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_cargo/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml new file mode 100644 index 0000000000000..9f644a1a39a50 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "fail-clippy" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/clippy.toml new file mode 100644 index 0000000000000..5e8e48b636b63 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/clippy.toml @@ -0,0 +1 @@ +msrv = "1.13" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_clippy/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml new file mode 100644 index 0000000000000..f0387cd90b80f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fail-file-attr" +version = "0.1.0" +rust-version = "1.59" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/src/main.rs new file mode 100644 index 0000000000000..27fe4771d2d6b --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/pass_file_attr/src/main.rs @@ -0,0 +1,13 @@ +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.13.0"] +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml new file mode 100644 index 0000000000000..a19d5b33fe563 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "warn-both-diff" +version = "0.1.0" +rust-version = "1.56.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/clippy.toml new file mode 100644 index 0000000000000..5e8e48b636b63 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/clippy.toml @@ -0,0 +1 @@ +msrv = "1.13" diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.rs new file mode 100644 index 0000000000000..5b91d5508678f --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.rs @@ -0,0 +1,11 @@ +#![deny(clippy::use_self)] + +pub struct Foo; + +impl Foo { + pub fn bar() -> Foo { + Foo + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.stderr new file mode 100644 index 0000000000000..eeae5b7b275e9 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.stderr @@ -0,0 +1,4 @@ +warning: the MSRV in `clippy.toml` and `Cargo.toml` differ; using `1.13.0` from `clippy.toml` + +warning: 1 warning emitted + diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs index 79b343da24700..99ca538b6e4a5 100644 --- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs @@ -1,3 +1,5 @@ +#[feature(lint_reasons)] + mod a; mod b; @@ -13,4 +15,15 @@ mod c3; mod from_other_module; mod other_module; +mod d; +#[path = "d.rs"] +mod d2; +#[path = "d.rs"] +#[expect(clippy::duplicate_mod)] +mod d3; +#[path = "d.rs"] +#[allow(clippy::duplicate_mod)] +mod d4; + + fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr index 00d7739c8a2ea..61df1ad5d501a 100644 --- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr @@ -1,5 +1,5 @@ error: file is loaded as a module multiple times: `$DIR/b.rs` - --> $DIR/main.rs:3:1 + --> $DIR/main.rs:5:1 | LL | mod b; | ^^^^^^ first loaded here @@ -11,7 +11,7 @@ LL | | mod b2; = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `$DIR/c.rs` - --> $DIR/main.rs:7:1 + --> $DIR/main.rs:9:1 | LL | mod c; | ^^^^^^ first loaded here @@ -25,7 +25,7 @@ LL | | mod c3; = help: replace all but one `mod` item with `use` items error: file is loaded as a module multiple times: `$DIR/from_other_module.rs` - --> $DIR/main.rs:13:1 + --> $DIR/main.rs:15:1 | LL | mod from_other_module; | ^^^^^^^^^^^^^^^^^^^^^^ first loaded here @@ -38,5 +38,16 @@ LL | | mod m; | = help: replace all but one `mod` item with `use` items -error: aborting due to 3 previous errors +error: file is loaded as a module multiple times: `$DIR/b.rs` + --> $DIR/main.rs:18:1 + | +LL | mod d; + | ^^^^^^ first loaded here +LL | / #[path = "d.rs"] +LL | | mod d2; + | |_______^ loaded again here + | + = help: replace all but one `mod` item with `use` items + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr index 2abb4e3e06e64..98697e001f99a 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr +++ b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr @@ -1,2 +1,2 @@ -Using config file `$SRC_DIR/tests/ui-cargo/multiple_config_files/warn/.clippy.toml` -Warning: `$SRC_DIR/tests/ui-cargo/multiple_config_files/warn/clippy.toml` will be ignored. +Using config file `$SRC_DIR/.clippy.toml` +Warning: `$SRC_DIR/clippy.toml` will be ignored. diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed index a5a6f20ddd54a..9f299d7dec720 100644 --- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -45,7 +45,12 @@ impl EarlyLintPass for Pass { if predicate { db.note(note_msg); } - }) + }); + + // Issue #8798 + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.help(help_msg).help(help_msg); + }); } } diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs index 6d783aa0786bd..2b113f555e46b 100644 --- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs @@ -55,7 +55,12 @@ impl EarlyLintPass for Pass { if predicate { db.note(note_msg); } - }) + }); + + // Issue #8798 + span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { + db.help(help_msg).help(help_msg); + }); } } diff --git a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs new file mode 100644 index 0000000000000..c8961d5e1f0bd --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.rs @@ -0,0 +1,30 @@ +#![deny(clippy::internal)] +#![feature(rustc_private)] + +#[macro_use] +extern crate clippy_lints; +use clippy_lints::deprecated_lints::ClippyDeprecatedLint; + +declare_deprecated_lint! { + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// TODO + #[clippy::version = "1.63.0"] + pub COOL_LINT_DEFAULT, + "default deprecation note" +} + +declare_deprecated_lint! { + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// This lint has been replaced by `cooler_lint` + #[clippy::version = "1.63.0"] + pub COOL_LINT, + "this lint has been replaced by `cooler_lint`" +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr new file mode 100644 index 0000000000000..ca26b649f986a --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/default_deprecation_reason.stderr @@ -0,0 +1,22 @@ +error: the lint `COOL_LINT_DEFAULT` has the default deprecation reason + --> $DIR/default_deprecation_reason.rs:8:1 + | +LL | / declare_deprecated_lint! { +LL | | /// ### What it does +LL | | /// Nothing. This lint has been deprecated. +LL | | /// +... | +LL | | "default deprecation note" +LL | | } + | |_^ + | +note: the lint level is defined here + --> $DIR/default_deprecation_reason.rs:1:9 + | +LL | #![deny(clippy::internal)] + | ^^^^^^^^^^^^^^^^ + = note: `#[deny(clippy::default_deprecation_reason)]` implied by `#[deny(clippy::internal)]` + = note: this error originates in the macro `declare_deprecated_lint` (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/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs index 9f283337c7e13..5bd2c2799f036 100644 --- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs +++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs @@ -127,3 +127,11 @@ macro_rules! ptr_as_ptr_cast { $ptr as *const i32 }; } + +#[macro_export] +macro_rules! manual_rem_euclid { + () => { + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + }; +} diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index ed7b17651e675..a89a06308d093 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -72,3 +72,17 @@ pub fn mini_macro(_: TokenStream) -> TokenStream { } ) } + +#[proc_macro_derive(ExtraLifetimeDerive)] +#[allow(unused)] +pub fn extra_lifetime(_input: TokenStream) -> TokenStream { + quote!( + pub struct ExtraLifetime; + + impl<'b> ExtraLifetime { + pub fn something<'c>() -> Self { + Self + } + } + ) +} diff --git a/src/tools/clippy/tests/ui/escape_analysis.rs b/src/tools/clippy/tests/ui/boxed_local.rs similarity index 97% rename from src/tools/clippy/tests/ui/escape_analysis.rs rename to src/tools/clippy/tests/ui/boxed_local.rs index 13e2b6c7a2e76..4639f00a8d830 100644 --- a/src/tools/clippy/tests/ui/escape_analysis.rs +++ b/src/tools/clippy/tests/ui/boxed_local.rs @@ -1,4 +1,5 @@ #![feature(box_syntax)] +#![feature(lint_reasons)] #![allow( clippy::borrowed_box, clippy::needless_pass_by_value, @@ -202,3 +203,7 @@ mod issue4804 { fn foo(x: Box<u32>) {} } } + +fn check_expect(#[expect(clippy::boxed_local)] x: Box<A>) { + x.foo(); +} diff --git a/src/tools/clippy/tests/ui/escape_analysis.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr similarity index 81% rename from src/tools/clippy/tests/ui/escape_analysis.stderr rename to src/tools/clippy/tests/ui/boxed_local.stderr index 4a82b4419f997..9036529f39c51 100644 --- a/src/tools/clippy/tests/ui/escape_analysis.stderr +++ b/src/tools/clippy/tests/ui/boxed_local.stderr @@ -1,5 +1,5 @@ error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:40:13 + --> $DIR/boxed_local.rs:41:13 | LL | fn warn_arg(x: Box<A>) { | ^ @@ -7,19 +7,19 @@ LL | fn warn_arg(x: Box<A>) { = note: `-D clippy::boxed-local` implied by `-D warnings` error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:131:12 + --> $DIR/boxed_local.rs:132:12 | LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {} | ^^^^^^^^^^^ error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:195:44 + --> $DIR/boxed_local.rs:196:44 | LL | fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 { | ^ error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:202:16 + --> $DIR/boxed_local.rs:203:16 | LL | fn foo(x: Box<u32>) {} | ^ diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs index ee3fdfabe9d8a..82dce81979fd9 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] #![allow(clippy::if_same_then_else, clippy::branches_sharing_code)] @@ -84,3 +85,18 @@ fn main() { assert!(x.is_ok(), "{:?}", x.unwrap_err()); // ok, it's a common test pattern } + +fn check_expect() { + let x = Some(()); + if x.is_some() { + #[expect(clippy::unnecessary_unwrap)] + x.unwrap(); // unnecessary + #[expect(clippy::unnecessary_unwrap)] + x.expect("an error message"); // unnecessary + } else { + #[expect(clippy::panicking_unwrap)] + x.unwrap(); // will panic + #[expect(clippy::panicking_unwrap)] + x.expect("an error message"); // will panic + } +} diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index 3413159280217..ef68827422233 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -1,5 +1,5 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> $DIR/simple_conditionals.rs:39:9 + --> $DIR/simple_conditionals.rs:40:9 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -7,13 +7,13 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/simple_conditionals.rs:1:35 + --> $DIR/simple_conditionals.rs:2:35 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_some` - --> $DIR/simple_conditionals.rs:40:9 + --> $DIR/simple_conditionals.rs:41:9 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -22,7 +22,7 @@ LL | x.expect("an error message"); // unnecessary | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:42:9 + --> $DIR/simple_conditionals.rs:43:9 | LL | if x.is_some() { | ----------- because of this check @@ -31,13 +31,13 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/simple_conditionals.rs:1:9 + --> $DIR/simple_conditionals.rs:2:9 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `expect()` will always panic - --> $DIR/simple_conditionals.rs:43:9 + --> $DIR/simple_conditionals.rs:44:9 | LL | if x.is_some() { | ----------- because of this check @@ -46,7 +46,7 @@ LL | x.expect("an error message"); // will panic | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:46:9 + --> $DIR/simple_conditionals.rs:47:9 | LL | if x.is_none() { | ----------- because of this check @@ -54,7 +54,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_none` - --> $DIR/simple_conditionals.rs:48:9 + --> $DIR/simple_conditionals.rs:49:9 | LL | if x.is_none() { | -------------- help: try: `if let Some(..) = x` @@ -63,7 +63,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_some` - --> $DIR/simple_conditionals.rs:7:13 + --> $DIR/simple_conditionals.rs:8:13 | LL | if $a.is_some() { | --------------- help: try: `if let Some(..) = x` @@ -76,7 +76,7 @@ LL | m!(x); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: called `unwrap` on `x` after checking its variant with `is_ok` - --> $DIR/simple_conditionals.rs:56:9 + --> $DIR/simple_conditionals.rs:57:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok(..) = x` @@ -84,7 +84,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_ok` - --> $DIR/simple_conditionals.rs:57:9 + --> $DIR/simple_conditionals.rs:58:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok(..) = x` @@ -93,7 +93,7 @@ LL | x.expect("an error message"); // unnecessary | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> $DIR/simple_conditionals.rs:58:9 + --> $DIR/simple_conditionals.rs:59:9 | LL | if x.is_ok() { | --------- because of this check @@ -102,7 +102,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:60:9 + --> $DIR/simple_conditionals.rs:61:9 | LL | if x.is_ok() { | --------- because of this check @@ -111,7 +111,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: this call to `expect()` will always panic - --> $DIR/simple_conditionals.rs:61:9 + --> $DIR/simple_conditionals.rs:62:9 | LL | if x.is_ok() { | --------- because of this check @@ -120,7 +120,7 @@ LL | x.expect("an error message"); // will panic | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> $DIR/simple_conditionals.rs:62:9 + --> $DIR/simple_conditionals.rs:63:9 | LL | if x.is_ok() { | ------------ help: try: `if let Err(..) = x` @@ -129,7 +129,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:65:9 + --> $DIR/simple_conditionals.rs:66:9 | LL | if x.is_err() { | ---------- because of this check @@ -137,7 +137,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_err` - --> $DIR/simple_conditionals.rs:66:9 + --> $DIR/simple_conditionals.rs:67:9 | LL | if x.is_err() { | ------------- help: try: `if let Err(..) = x` @@ -146,7 +146,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_err` - --> $DIR/simple_conditionals.rs:68:9 + --> $DIR/simple_conditionals.rs:69:9 | LL | if x.is_err() { | ------------- help: try: `if let Ok(..) = x` @@ -155,7 +155,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> $DIR/simple_conditionals.rs:69:9 + --> $DIR/simple_conditionals.rs:70:9 | LL | if x.is_err() { | ---------- because of this check diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr index 77a3c2ba4ad09..8da2965c63512 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr @@ -33,7 +33,7 @@ LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> { | ^^^^^^^^^^^ expected `usize`, found closure | = note: expected type `usize` - found closure `[closure@$DIR/ice-6251.rs:4:44: 4:55]` + found closure `[closure@$DIR/ice-6251.rs:4:44: 4:53]` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index d930d486fde65..a1e37e7317b2e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -25,10 +25,10 @@ error[E0046]: not all trait items implemented, missing: `VAL` --> $DIR/ice-6252.rs:10:1 | LL | const VAL: T; - | ------------- `VAL` from trait + | ------------ `VAL` from trait ... LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation error: constant expression depends on a generic parameter --> $DIR/ice-6252.rs:13:9 diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs index 48c5e9537d6d0..62af545db503b 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs @@ -31,4 +31,9 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); //^ there should be no lints on this line +// issue #8493 +thread_local! { + static THREAD_LOCAL: Cell<i32> = const { Cell::new(0) }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed new file mode 100644 index 0000000000000..f1abfdcd6ce69 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed @@ -0,0 +1,21 @@ +// run-rustfix +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +use std::collections::HashMap; + +#[derive(Default)] +struct Iter { + iter: std::iter::Empty<usize>, +} + +fn main() { + // Do lint. + let _ = std::iter::empty::<usize>(); + let _ = std::iter::empty::<HashMap<usize, usize>>(); + let _foo: std::iter::Empty<usize> = std::iter::empty(); + + // Do not lint. + let _ = Vec::<usize>::default(); + let _ = String::default(); + let _ = Iter::default(); +} diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs new file mode 100644 index 0000000000000..2630519c46da4 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs @@ -0,0 +1,21 @@ +// run-rustfix +#![warn(clippy::default_instead_of_iter_empty)] +#![allow(dead_code)] +use std::collections::HashMap; + +#[derive(Default)] +struct Iter { + iter: std::iter::Empty<usize>, +} + +fn main() { + // Do lint. + let _ = std::iter::Empty::<usize>::default(); + let _ = std::iter::Empty::<HashMap<usize, usize>>::default(); + let _foo: std::iter::Empty<usize> = std::iter::Empty::default(); + + // Do not lint. + let _ = Vec::<usize>::default(); + let _ = String::default(); + let _ = Iter::default(); +} diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr new file mode 100644 index 0000000000000..460fc84def8a5 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr @@ -0,0 +1,22 @@ +error: `std::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty.rs:13:13 + | +LL | let _ = std::iter::Empty::<usize>::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty::<usize>()` + | + = note: `-D clippy::default-instead-of-iter-empty` implied by `-D warnings` + +error: `std::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty.rs:14:13 + | +LL | let _ = std::iter::Empty::<HashMap<usize, usize>>::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty::<HashMap<usize, usize>>()` + +error: `std::iter::empty()` is the more idiomatic way + --> $DIR/default_instead_of_iter_empty.rs:15:41 + | +LL | let _foo: std::iter::Empty<usize> = std::iter::Empty::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs index 4e46bf1399173..b276c384c04ea 100644 --- a/src/tools/clippy/tests/ui/derive.rs +++ b/src/tools/clippy/tests/ui/derive.rs @@ -1,7 +1,7 @@ -#![feature(untagged_unions)] #![allow(dead_code)] #![warn(clippy::expl_impl_clone_on_copy)] + #[derive(Copy)] struct Qux; diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr index e5184bd1407c0..2a4abb0c5193a 100644 --- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr +++ b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr @@ -8,12 +8,8 @@ LL | #[derive(Hash)] note: `PartialEq` implemented here --> $DIR/derive_hash_xor_eq.rs:15:1 | -LL | / impl PartialEq for Bar { -LL | | fn eq(&self, _: &Bar) -> bool { -LL | | true -LL | | } -LL | | } - | |_^ +LL | impl PartialEq for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Hash` but have implemented `PartialEq` explicitly @@ -25,12 +21,8 @@ LL | #[derive(Hash)] note: `PartialEq` implemented here --> $DIR/derive_hash_xor_eq.rs:24:1 | -LL | / impl PartialEq<Baz> for Baz { -LL | | fn eq(&self, _: &Baz) -> bool { -LL | | true -LL | | } -LL | | } - | |_^ +LL | impl PartialEq<Baz> for Baz { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Hash` explicitly but have derived `PartialEq` diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr index 32896c99dad0a..baf8341aba908 100644 --- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr @@ -8,12 +8,8 @@ LL | #[derive(Ord, PartialEq, Eq)] note: `PartialOrd` implemented here --> $DIR/derive_ord_xor_partial_ord.rs:24:1 | -LL | / impl PartialOrd for DeriveOrd { -LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { -LL | | Some(other.cmp(self)) -LL | | } -LL | | } - | |_^ +LL | impl PartialOrd for DeriveOrd { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly @@ -25,12 +21,8 @@ LL | #[derive(Ord, PartialEq, Eq)] note: `PartialOrd` implemented here --> $DIR/derive_ord_xor_partial_ord.rs:33:1 | -LL | / impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable { -LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { -LL | | Some(other.cmp(self)) -LL | | } -LL | | } - | |_^ +LL | impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index b2bf7c4e360a0..efed12ee2ef6f 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -158,4 +158,25 @@ enum Phase { PostLookup, } +mod issue9018 { + enum DoLint { + _TypeCreate, + _TypeRead, + _TypeUpdate, + _TypeDestroy, + } + + enum DoLintToo { + _CreateType, + _UpdateType, + _DeleteType, + } + + enum DoNotLint { + _Foo, + _Bar, + _Baz, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index 8a3265086e84f..7342aff80f016 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -120,5 +120,30 @@ LL | | } | = help: remove the postfixes and use full paths to the variants instead of glob imports -error: aborting due to 12 previous errors +error: all variants have the same prefix: `_Type` + --> $DIR/enum_variants.rs:162:5 + | +LL | / enum DoLint { +LL | | _TypeCreate, +LL | | _TypeRead, +LL | | _TypeUpdate, +LL | | _TypeDestroy, +LL | | } + | |_____^ + | + = help: remove the prefixes and use full paths to the variants instead of glob imports + +error: all variants have the same postfix: `Type` + --> $DIR/enum_variants.rs:169:5 + | +LL | / enum DoLintToo { +LL | | _CreateType, +LL | | _UpdateType, +LL | | _DeleteType, +LL | | } + | |_____^ + | + = help: remove the postfixes and use full paths to the variants instead of glob imports + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed new file mode 100644 index 0000000000000..d4ff1b1566dc6 --- /dev/null +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed @@ -0,0 +1,214 @@ +// run-rustfix + +#![warn(clippy::explicit_auto_deref)] +#![allow( + dead_code, + unused_braces, + clippy::borrowed_box, + clippy::needless_borrow, + clippy::needless_return, + clippy::ptr_arg, + clippy::redundant_field_names, + clippy::too_many_arguments, + clippy::borrow_deref_ref, + clippy::let_unit_value +)] + +trait CallableStr { + type T: Fn(&str); + fn callable_str(&self) -> Self::T; +} +impl CallableStr for () { + type T = fn(&str); + fn callable_str(&self) -> Self::T { + fn f(_: &str) {} + f + } +} +impl CallableStr for i32 { + type T = <() as CallableStr>::T; + fn callable_str(&self) -> Self::T { + ().callable_str() + } +} + +trait CallableT<U: ?Sized> { + type T: Fn(&U); + fn callable_t(&self) -> Self::T; +} +impl<U: ?Sized> CallableT<U> for () { + type T = fn(&U); + fn callable_t(&self) -> Self::T { + fn f<U: ?Sized>(_: &U) {} + f::<U> + } +} +impl<U: ?Sized> CallableT<U> for i32 { + type T = <() as CallableT<U>>::T; + fn callable_t(&self) -> Self::T { + ().callable_t() + } +} + +fn f_str(_: &str) {} +fn f_string(_: &String) {} +fn f_t<T>(_: T) {} +fn f_ref_t<T: ?Sized>(_: &T) {} + +fn f_str_t<T>(_: &str, _: T) {} + +fn f_box_t<T>(_: &Box<T>) {} + +extern "C" { + fn var(_: u32, ...); +} + +fn main() { + let s = String::new(); + + let _: &str = &s; + let _ = &*s; // Don't lint. Inferred type would change. + let _: &_ = &*s; // Don't lint. Inferred type would change. + + f_str(&s); + f_t(&*s); // Don't lint. Inferred type would change. + f_ref_t(&*s); // Don't lint. Inferred type would change. + + f_str_t(&s, &*s); // Don't lint second param. + + let b = Box::new(Box::new(Box::new(5))); + let _: &Box<i32> = &b; + let _: &Box<_> = &**b; // Don't lint. Inferred type would change. + + f_box_t(&**b); // Don't lint. Inferred type would change. + + let c = |_x: &str| (); + c(&s); + + let c = |_x| (); + c(&*s); // Don't lint. Inferred type would change. + + fn _f(x: &String) -> &str { + x + } + + fn _f1(x: &String) -> &str { + { x } + } + + fn _f2(x: &String) -> &str { + { x } + } + + fn _f3(x: &Box<Box<Box<i32>>>) -> &Box<i32> { + x + } + + fn _f4( + x: String, + f1: impl Fn(&str), + f2: &dyn Fn(&str), + f3: fn(&str), + f4: impl CallableStr, + f5: <() as CallableStr>::T, + f6: <i32 as CallableStr>::T, + f7: &dyn CallableStr<T = fn(&str)>, + f8: impl CallableT<str>, + f9: <() as CallableT<str>>::T, + f10: <i32 as CallableT<str>>::T, + f11: &dyn CallableT<str, T = fn(&str)>, + ) { + f1(&x); + f2(&x); + f3(&x); + f4.callable_str()(&x); + f5(&x); + f6(&x); + f7.callable_str()(&x); + f8.callable_t()(&x); + f9(&x); + f10(&x); + f11.callable_t()(&x); + } + + struct S1<'a>(&'a str); + let _ = S1(&s); + + struct S2<'a> { + s: &'a str, + } + let _ = S2 { s: &s }; + + struct S3<'a, T: ?Sized>(&'a T); + let _ = S3(&*s); // Don't lint. Inferred type would change. + + struct S4<'a, T: ?Sized> { + s: &'a T, + } + let _ = S4 { s: &*s }; // Don't lint. Inferred type would change. + + enum E1<'a> { + S1(&'a str), + S2 { s: &'a str }, + } + impl<'a> E1<'a> { + fn m1(s: &'a String) { + let _ = Self::S1(s); + let _ = Self::S2 { s: s }; + } + } + let _ = E1::S1(&s); + let _ = E1::S2 { s: &s }; + + enum E2<'a, T: ?Sized> { + S1(&'a T), + S2 { s: &'a T }, + } + let _ = E2::S1(&*s); // Don't lint. Inferred type would change. + let _ = E2::S2 { s: &*s }; // Don't lint. Inferred type would change. + + let ref_s = &s; + let _: &String = &*ref_s; // Don't lint reborrow. + f_string(&*ref_s); // Don't lint reborrow. + + struct S5 { + foo: u32, + } + let b = Box::new(Box::new(S5 { foo: 5 })); + let _ = b.foo; + let _ = b.foo; + let _ = b.foo; + + struct S6 { + foo: S5, + } + impl core::ops::Deref for S6 { + type Target = S5; + fn deref(&self) -> &Self::Target { + &self.foo + } + } + let s6 = S6 { foo: S5 { foo: 5 } }; + let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo` + + let ref_str = &"foo"; + let _ = f_str(ref_str); + let ref_ref_str = &ref_str; + let _ = f_str(ref_ref_str); + + fn _f5(x: &u32) -> u32 { + if true { + *x + } else { + return *x; + } + } + + f_str(&&ref_str); // `needless_borrow` will suggest removing both references + f_str(&ref_str); // `needless_borrow` will suggest removing only one reference + + let x = &&40; + unsafe { + var(0, &**x); + } +} diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs new file mode 100644 index 0000000000000..99294a7947bf1 --- /dev/null +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs @@ -0,0 +1,214 @@ +// run-rustfix + +#![warn(clippy::explicit_auto_deref)] +#![allow( + dead_code, + unused_braces, + clippy::borrowed_box, + clippy::needless_borrow, + clippy::needless_return, + clippy::ptr_arg, + clippy::redundant_field_names, + clippy::too_many_arguments, + clippy::borrow_deref_ref, + clippy::let_unit_value +)] + +trait CallableStr { + type T: Fn(&str); + fn callable_str(&self) -> Self::T; +} +impl CallableStr for () { + type T = fn(&str); + fn callable_str(&self) -> Self::T { + fn f(_: &str) {} + f + } +} +impl CallableStr for i32 { + type T = <() as CallableStr>::T; + fn callable_str(&self) -> Self::T { + ().callable_str() + } +} + +trait CallableT<U: ?Sized> { + type T: Fn(&U); + fn callable_t(&self) -> Self::T; +} +impl<U: ?Sized> CallableT<U> for () { + type T = fn(&U); + fn callable_t(&self) -> Self::T { + fn f<U: ?Sized>(_: &U) {} + f::<U> + } +} +impl<U: ?Sized> CallableT<U> for i32 { + type T = <() as CallableT<U>>::T; + fn callable_t(&self) -> Self::T { + ().callable_t() + } +} + +fn f_str(_: &str) {} +fn f_string(_: &String) {} +fn f_t<T>(_: T) {} +fn f_ref_t<T: ?Sized>(_: &T) {} + +fn f_str_t<T>(_: &str, _: T) {} + +fn f_box_t<T>(_: &Box<T>) {} + +extern "C" { + fn var(_: u32, ...); +} + +fn main() { + let s = String::new(); + + let _: &str = &*s; + let _ = &*s; // Don't lint. Inferred type would change. + let _: &_ = &*s; // Don't lint. Inferred type would change. + + f_str(&*s); + f_t(&*s); // Don't lint. Inferred type would change. + f_ref_t(&*s); // Don't lint. Inferred type would change. + + f_str_t(&*s, &*s); // Don't lint second param. + + let b = Box::new(Box::new(Box::new(5))); + let _: &Box<i32> = &**b; + let _: &Box<_> = &**b; // Don't lint. Inferred type would change. + + f_box_t(&**b); // Don't lint. Inferred type would change. + + let c = |_x: &str| (); + c(&*s); + + let c = |_x| (); + c(&*s); // Don't lint. Inferred type would change. + + fn _f(x: &String) -> &str { + &**x + } + + fn _f1(x: &String) -> &str { + { &**x } + } + + fn _f2(x: &String) -> &str { + &**{ x } + } + + fn _f3(x: &Box<Box<Box<i32>>>) -> &Box<i32> { + &***x + } + + fn _f4( + x: String, + f1: impl Fn(&str), + f2: &dyn Fn(&str), + f3: fn(&str), + f4: impl CallableStr, + f5: <() as CallableStr>::T, + f6: <i32 as CallableStr>::T, + f7: &dyn CallableStr<T = fn(&str)>, + f8: impl CallableT<str>, + f9: <() as CallableT<str>>::T, + f10: <i32 as CallableT<str>>::T, + f11: &dyn CallableT<str, T = fn(&str)>, + ) { + f1(&*x); + f2(&*x); + f3(&*x); + f4.callable_str()(&*x); + f5(&*x); + f6(&*x); + f7.callable_str()(&*x); + f8.callable_t()(&*x); + f9(&*x); + f10(&*x); + f11.callable_t()(&*x); + } + + struct S1<'a>(&'a str); + let _ = S1(&*s); + + struct S2<'a> { + s: &'a str, + } + let _ = S2 { s: &*s }; + + struct S3<'a, T: ?Sized>(&'a T); + let _ = S3(&*s); // Don't lint. Inferred type would change. + + struct S4<'a, T: ?Sized> { + s: &'a T, + } + let _ = S4 { s: &*s }; // Don't lint. Inferred type would change. + + enum E1<'a> { + S1(&'a str), + S2 { s: &'a str }, + } + impl<'a> E1<'a> { + fn m1(s: &'a String) { + let _ = Self::S1(&**s); + let _ = Self::S2 { s: &**s }; + } + } + let _ = E1::S1(&*s); + let _ = E1::S2 { s: &*s }; + + enum E2<'a, T: ?Sized> { + S1(&'a T), + S2 { s: &'a T }, + } + let _ = E2::S1(&*s); // Don't lint. Inferred type would change. + let _ = E2::S2 { s: &*s }; // Don't lint. Inferred type would change. + + let ref_s = &s; + let _: &String = &*ref_s; // Don't lint reborrow. + f_string(&*ref_s); // Don't lint reborrow. + + struct S5 { + foo: u32, + } + let b = Box::new(Box::new(S5 { foo: 5 })); + let _ = b.foo; + let _ = (*b).foo; + let _ = (**b).foo; + + struct S6 { + foo: S5, + } + impl core::ops::Deref for S6 { + type Target = S5; + fn deref(&self) -> &Self::Target { + &self.foo + } + } + let s6 = S6 { foo: S5 { foo: 5 } }; + let _ = (*s6).foo; // Don't lint. `S6` also has a field named `foo` + + let ref_str = &"foo"; + let _ = f_str(*ref_str); + let ref_ref_str = &ref_str; + let _ = f_str(**ref_ref_str); + + fn _f5(x: &u32) -> u32 { + if true { + *x + } else { + return *x; + } + } + + f_str(&&*ref_str); // `needless_borrow` will suggest removing both references + f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference + + let x = &&40; + unsafe { + var(0, &**x); + } +} diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr new file mode 100644 index 0000000000000..55f956e37aed7 --- /dev/null +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr @@ -0,0 +1,196 @@ +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:69:20 + | +LL | let _: &str = &*s; + | ^^ help: try this: `s` + | + = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:73:12 + | +LL | f_str(&*s); + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:77:14 + | +LL | f_str_t(&*s, &*s); // Don't lint second param. + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:80:25 + | +LL | let _: &Box<i32> = &**b; + | ^^^ help: try this: `b` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:86:8 + | +LL | c(&*s); + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:92:9 + | +LL | &**x + | ^^^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:96:11 + | +LL | { &**x } + | ^^^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:100:9 + | +LL | &**{ x } + | ^^^^^^^^ help: try this: `{ x }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:104:9 + | +LL | &***x + | ^^^^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:121:13 + | +LL | f1(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:122:13 + | +LL | f2(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:123:13 + | +LL | f3(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:124:28 + | +LL | f4.callable_str()(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:125:13 + | +LL | f5(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:126:13 + | +LL | f6(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:127:28 + | +LL | f7.callable_str()(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:128:26 + | +LL | f8.callable_t()(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:129:13 + | +LL | f9(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:130:14 + | +LL | f10(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:131:27 + | +LL | f11.callable_t()(&*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:135:17 + | +LL | let _ = S1(&*s); + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:140:22 + | +LL | let _ = S2 { s: &*s }; + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:156:30 + | +LL | let _ = Self::S1(&**s); + | ^^^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:157:35 + | +LL | let _ = Self::S2 { s: &**s }; + | ^^^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:160:21 + | +LL | let _ = E1::S1(&*s); + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:161:26 + | +LL | let _ = E1::S2 { s: &*s }; + | ^^ help: try this: `s` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:179:13 + | +LL | let _ = (*b).foo; + | ^^^^ help: try this: `b` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:180:13 + | +LL | let _ = (**b).foo; + | ^^^^^ help: try this: `b` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:195:19 + | +LL | let _ = f_str(*ref_str); + | ^^^^^^^^ help: try this: `ref_str` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:197:19 + | +LL | let _ = f_str(**ref_ref_str); + | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:207:13 + | +LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references + | ^^^^^^^^ help: try this: `ref_str` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:208:12 + | +LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference + | ^^^^^^^^^^ help: try this: `ref_str` + +error: aborting due to 32 previous errors + diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed index 92f27e68549a3..523cae183ee6e 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed @@ -4,7 +4,8 @@ unused_variables, clippy::clone_double_ref, clippy::needless_borrow, - clippy::borrow_deref_ref + clippy::borrow_deref_ref, + clippy::explicit_auto_deref )] #![warn(clippy::explicit_deref_methods)] diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs index d118607f992b9..0bbc1ae57cdf6 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs @@ -4,7 +4,8 @@ unused_variables, clippy::clone_double_ref, clippy::needless_borrow, - clippy::borrow_deref_ref + clippy::borrow_deref_ref, + clippy::explicit_auto_deref )] #![warn(clippy::explicit_deref_methods)] diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr index 8e8b358972be7..4b10ed1377b0d 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr @@ -1,5 +1,5 @@ error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:35:19 + --> $DIR/explicit_deref_methods.rs:36:19 | LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try this: `&*a` @@ -7,67 +7,67 @@ LL | let b: &str = a.deref(); = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` error: explicit `deref_mut` method call - --> $DIR/explicit_deref_methods.rs:37:23 + --> $DIR/explicit_deref_methods.rs:38:23 | LL | let b: &mut str = a.deref_mut(); | ^^^^^^^^^^^^^ help: try this: `&mut **a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:40:39 + --> $DIR/explicit_deref_methods.rs:41:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:40:50 + --> $DIR/explicit_deref_methods.rs:41:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:42:20 + --> $DIR/explicit_deref_methods.rs:43:20 | LL | println!("{}", a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:45:11 + --> $DIR/explicit_deref_methods.rs:46:11 | LL | match a.deref() { | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:49:28 + --> $DIR/explicit_deref_methods.rs:50:28 | LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:51:13 + --> $DIR/explicit_deref_methods.rs:52:13 | LL | let b = just_return(a).deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:53:28 + --> $DIR/explicit_deref_methods.rs:54:28 | LL | let b: String = concat(just_return(a).deref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:55:19 + --> $DIR/explicit_deref_methods.rs:56:19 | LL | let b: &str = a.deref().deref(); | ^^^^^^^^^^^^^^^^^ help: try this: `&**a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:58:13 + --> $DIR/explicit_deref_methods.rs:59:13 | LL | let b = opt_a.unwrap().deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:84:31 + --> $DIR/explicit_deref_methods.rs:85:31 | LL | let b: &str = expr_deref!(a.deref()); | ^^^^^^^^^ help: try this: `&*a` diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs index f76127a7105fd..d6631e0129000 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs @@ -1,3 +1,5 @@ +// aux-build:proc_macro_derive.rs + #![allow( unused, dead_code, @@ -7,6 +9,9 @@ )] #![warn(clippy::extra_unused_lifetimes)] +#[macro_use] +extern crate proc_macro_derive; + fn empty() {} fn used_lt<'a>(x: &'a u8) {} @@ -114,4 +119,11 @@ mod second_case { } } +// Should not lint +#[derive(ExtraLifetimeDerive)] +struct Human<'a> { + pub bones: i32, + pub name: &'a str, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr index fcc12d4ce14b9..26ebc3976dfca 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:14:14 + --> $DIR/extra_unused_lifetimes.rs:19:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -7,31 +7,31 @@ LL | fn unused_lt<'a>(x: u8) {} = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:41:10 + --> $DIR/extra_unused_lifetimes.rs:46:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:67:22 + --> $DIR/extra_unused_lifetimes.rs:72:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ error: this lifetime isn't used in the impl - --> $DIR/extra_unused_lifetimes.rs:78:10 + --> $DIR/extra_unused_lifetimes.rs:83:10 | LL | impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar { | ^^ error: this lifetime isn't used in the impl - --> $DIR/extra_unused_lifetimes.rs:84:10 + --> $DIR/extra_unused_lifetimes.rs:89:10 | LL | impl<'b> Scalar { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:85:26 + --> $DIR/extra_unused_lifetimes.rs:90:26 | LL | pub fn something<'c>() -> Self { | ^^ diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs index ef9567455008b..2598c2ab426d3 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else.rs @@ -6,7 +6,9 @@ clippy::no_effect, clippy::unused_unit, clippy::zero_divided_by_zero, - clippy::branches_sharing_code + clippy::branches_sharing_code, + dead_code, + unreachable_code )] struct Foo { @@ -155,4 +157,61 @@ mod issue_5698 { } } +mod issue_8836 { + fn do_not_lint() { + if true { + todo!() + } else { + todo!() + } + if true { + todo!(); + } else { + todo!(); + } + if true { + unimplemented!() + } else { + unimplemented!() + } + if true { + unimplemented!(); + } else { + unimplemented!(); + } + + if true { + println!("FOO"); + todo!(); + } else { + println!("FOO"); + todo!(); + } + + if true { + println!("FOO"); + unimplemented!(); + } else { + println!("FOO"); + unimplemented!(); + } + + if true { + println!("FOO"); + todo!() + } else { + println!("FOO"); + todo!() + } + + if true { + println!("FOO"); + unimplemented!() + } else { + println!("FOO"); + unimplemented!() + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr index 2f38052fc209e..2cdf442486a30 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:21:13 + --> $DIR/if_same_then_else.rs:23:13 | LL | if true { | _____________^ @@ -13,7 +13,7 @@ LL | | } else { | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/if_same_then_else.rs:29:12 + --> $DIR/if_same_then_else.rs:31:12 | LL | } else { | ____________^ @@ -26,7 +26,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:65:21 + --> $DIR/if_same_then_else.rs:67:21 | LL | let _ = if true { | _____________________^ @@ -35,7 +35,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:67:12 + --> $DIR/if_same_then_else.rs:69:12 | LL | } else { | ____________^ @@ -45,7 +45,7 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:72:21 + --> $DIR/if_same_then_else.rs:74:21 | LL | let _ = if true { | _____________________^ @@ -54,7 +54,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:74:12 + --> $DIR/if_same_then_else.rs:76:12 | LL | } else { | ____________^ @@ -64,7 +64,7 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:88:21 + --> $DIR/if_same_then_else.rs:90:21 | LL | let _ = if true { | _____________________^ @@ -73,7 +73,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:90:12 + --> $DIR/if_same_then_else.rs:92:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else.rs:95:13 + --> $DIR/if_same_then_else.rs:97:13 | LL | if true { | _____________^ @@ -96,7 +96,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:102:12 + --> $DIR/if_same_then_else.rs:104:12 | LL | } else { | ____________^ diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed index a51f7bc6a29ff..5e55b8b673919 100644 --- a/src/tools/clippy/tests/ui/implicit_return.fixed +++ b/src/tools/clippy/tests/ui/implicit_return.fixed @@ -1,5 +1,5 @@ // run-rustfix - +#![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] @@ -128,3 +128,13 @@ async fn foo() -> bool { } fn main() {} + +fn check_expect() -> bool { + if true { + // no error! + return true; + } + + #[expect(clippy::implicit_return)] + true +} diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs index 03f8ec49d51e5..76f0a98035209 100644 --- a/src/tools/clippy/tests/ui/implicit_return.rs +++ b/src/tools/clippy/tests/ui/implicit_return.rs @@ -1,5 +1,5 @@ // run-rustfix - +#![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] @@ -128,3 +128,13 @@ async fn foo() -> bool { } fn main() {} + +fn check_expect() -> bool { + if true { + // no error! + return true; + } + + #[expect(clippy::implicit_return)] + true +} diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.rs b/src/tools/clippy/tests/ui/let_underscore_lock.rs index 539d74d1d4c9a..7a7c4e9249952 100644 --- a/src/tools/clippy/tests/ui/let_underscore_lock.rs +++ b/src/tools/clippy/tests/ui/let_underscore_lock.rs @@ -13,6 +13,10 @@ fn main() { let _ = rw.try_read(); let _ = rw.try_write(); + // These shouldn't throw an error. + let _ = m; + let _ = rw; + use parking_lot::{lock_api::RawMutex, Mutex, RwLock}; let p_m: Mutex<()> = Mutex::const_new(RawMutex::INIT, ()); @@ -24,4 +28,9 @@ fn main() { let p_rw = RwLock::new(0); let _ = p_rw.read(); let _ = p_rw.write(); + + // These shouldn't throw an error. + let _ = p_m; + let _ = p_m1; + let _ = p_rw; } diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.stderr b/src/tools/clippy/tests/ui/let_underscore_lock.stderr index 3a2bc17bf7b20..4365b48fabb9c 100644 --- a/src/tools/clippy/tests/ui/let_underscore_lock.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_lock.stderr @@ -48,7 +48,7 @@ LL | let _ = rw.try_write(); = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:19:5 + --> $DIR/let_underscore_lock.rs:23:5 | LL | let _ = p_m.lock(); | ^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = p_m.lock(); = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:22:5 + --> $DIR/let_underscore_lock.rs:26:5 | LL | let _ = p_m1.lock(); | ^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = p_m1.lock(); = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:25:5 + --> $DIR/let_underscore_lock.rs:29:5 | LL | let _ = p_rw.read(); | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = p_rw.read(); = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:26:5 + --> $DIR/let_underscore_lock.rs:30:5 | LL | let _ = p_rw.write(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/logic_bug.rs b/src/tools/clippy/tests/ui/logic_bug.rs index 4eaa2dd98eb2e..dd6b1db5f70a0 100644 --- a/src/tools/clippy/tests/ui/logic_bug.rs +++ b/src/tools/clippy/tests/ui/logic_bug.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::logic_bug)] @@ -24,3 +25,10 @@ fn equality_stuff() { let _ = a > b && a <= b; let _ = a > b && a == b; } + +fn check_expect() { + let a: i32 = unimplemented!(); + let b: i32 = unimplemented!(); + #[expect(clippy::logic_bug)] + let _ = a < b && a >= b; +} diff --git a/src/tools/clippy/tests/ui/logic_bug.stderr b/src/tools/clippy/tests/ui/logic_bug.stderr index 8f55e1c8ad859..4021fbf457053 100644 --- a/src/tools/clippy/tests/ui/logic_bug.stderr +++ b/src/tools/clippy/tests/ui/logic_bug.stderr @@ -1,60 +1,60 @@ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:10:13 + --> $DIR/logic_bug.rs:11:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | = note: `-D clippy::logic-bug` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:10:18 + --> $DIR/logic_bug.rs:11:18 | LL | let _ = a && b || a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:12:13 + --> $DIR/logic_bug.rs:13:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:12:22 + --> $DIR/logic_bug.rs:13:22 | LL | let _ = false && a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:22:13 + --> $DIR/logic_bug.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:22:13 + --> $DIR/logic_bug.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:23:13 + --> $DIR/logic_bug.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:23:13 + --> $DIR/logic_bug.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:24:13 + --> $DIR/logic_bug.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:24:13 + --> $DIR/logic_bug.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index a83c8ba0b6428..e612480d264bd 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -4,6 +4,7 @@ // run-rustfix // ignore-32bit +#![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] #![warn(clippy::macro_use_imports)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index e26a7545ea6f8..b34817cc3b269 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -4,6 +4,7 @@ // run-rustfix // ignore-32bit +#![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] #![allow(clippy::single_component_path_imports)] #![warn(clippy::macro_use_imports)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index 9028a636e7f7a..bf7b6edd0e314 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -1,28 +1,28 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:18:5 + --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:20:5 + --> $DIR/macro_use_imports.rs:21:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:22:5 + --> $DIR/macro_use_imports.rs:25: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::nested::string_add;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:24:5 + --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro};` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs new file mode 100644 index 0000000000000..8a1b05da9efc7 --- /dev/null +++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs @@ -0,0 +1,51 @@ +// aux-build:macro_rules.rs +// aux-build:macro_use_helper.rs +// aux-build:proc_macro_derive.rs +// ignore-32bit + +#![feature(lint_reasons)] +#![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] +#![allow(clippy::single_component_path_imports)] +#![warn(clippy::macro_use_imports)] + +#[macro_use] +extern crate macro_use_helper as mac; + +#[macro_use] +extern crate proc_macro_derive as mini_mac; + +mod a { + #[expect(clippy::macro_use_imports)] + #[macro_use] + use mac; + #[expect(clippy::macro_use_imports)] + #[macro_use] + use mini_mac; + #[expect(clippy::macro_use_imports)] + #[macro_use] + use mac::inner; + #[expect(clippy::macro_use_imports)] + #[macro_use] + use mac::inner::nested; + + #[derive(ClippyMiniMacroTest)] + struct Test; + + fn test() { + pub_macro!(); + inner_mod_macro!(); + pub_in_private_macro!(_var); + function_macro!(); + let v: ty_macro!() = Vec::default(); + + inner::try_err!(); + inner::foofoo!(); + nested::string_add!(); + } +} + +// issue #7015, ICE due to calling `module_children` with local `DefId` +#[macro_use] +use a as b; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_find.rs b/src/tools/clippy/tests/ui/manual_find.rs new file mode 100644 index 0000000000000..257fe045f78a1 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_find.rs @@ -0,0 +1,22 @@ +#![allow(unused)] +#![warn(clippy::manual_find)] + +fn vec_string(strings: Vec<String>) -> Option<String> { + for s in strings { + if s == String::new() { + return Some(s); + } + } + None +} + +fn tuple(arr: Vec<(String, i32)>) -> Option<String> { + for (s, _) in arr { + if s == String::new() { + return Some(s); + } + } + None +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_find.stderr b/src/tools/clippy/tests/ui/manual_find.stderr new file mode 100644 index 0000000000000..da0fd4aaef7d6 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_find.stderr @@ -0,0 +1,29 @@ +error: manual implementation of `Iterator::find` + --> $DIR/manual_find.rs:5:5 + | +LL | / for s in strings { +LL | | if s == String::new() { +LL | | return Some(s); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `strings.into_iter().find(|s| s == String::new())` + | + = note: `-D clippy::manual-find` implied by `-D warnings` + = note: you may need to dereference some variables + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find.rs:14:5 + | +LL | / for (s, _) in arr { +LL | | if s == String::new() { +LL | | return Some(s); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().map(|(s, _)| s).find(|s| s == String::new())` + | + = note: you may need to dereference some variables + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.fixed b/src/tools/clippy/tests/ui/manual_find_fixable.fixed new file mode 100644 index 0000000000000..36d1644c22bda --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_find_fixable.fixed @@ -0,0 +1,182 @@ +// run-rustfix + +#![allow(unused, clippy::needless_return)] +#![warn(clippy::manual_find)] + +use std::collections::HashMap; + +const ARRAY: &[u32; 5] = &[2, 7, 1, 9, 3]; + +fn lookup(n: u32) -> Option<u32> { + ARRAY.iter().find(|&&v| v == n).copied() +} + +fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> { + arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0) +} + +struct Data { + name: String, + is_true: bool, +} +fn with_struct(arr: Vec<Data>) -> Option<Data> { + arr.into_iter().find(|el| el.name.len() == 10) +} + +struct Tuple(usize, usize); +fn with_tuple_struct(arr: Vec<Tuple>) -> Option<usize> { + arr.into_iter().map(|Tuple(a, _)| a).find(|&a| a >= 3) +} + +struct A; +impl A { + fn should_keep(&self) -> bool { + true + } +} +fn with_method_call(arr: Vec<A>) -> Option<A> { + arr.into_iter().find(|el| el.should_keep()) +} + +fn with_closure(arr: Vec<u32>) -> Option<u32> { + let f = |el: u32| -> u32 { el + 10 }; + arr.into_iter().find(|&el| f(el) == 20) +} + +fn with_closure2(arr: HashMap<String, i32>) -> Option<i32> { + let f = |el: i32| -> bool { el == 10 }; + arr.values().find(|&&el| f(el)).copied() +} + +fn with_bool(arr: Vec<Data>) -> Option<Data> { + arr.into_iter().find(|el| el.is_true) +} + +fn with_side_effects(arr: Vec<u32>) -> Option<u32> { + for v in arr { + if v == 1 { + println!("side effect"); + return Some(v); + } + } + None +} + +fn with_else(arr: Vec<u32>) -> Option<u32> { + for el in arr { + if el % 2 == 0 { + return Some(el); + } else { + println!("{}", el); + } + } + None +} + +fn tuple_with_ref(v: [(u8, &u8); 3]) -> Option<u8> { + v.into_iter().map(|(_, &x)| x).find(|&x| x > 10) +} + +fn ref_to_tuple_with_ref(v: &[(u8, &u8)]) -> Option<u8> { + v.iter().map(|&(_, &x)| x).find(|&x| x > 10) +} + +fn explicit_ret(arr: Vec<i32>) -> Option<i32> { + arr.into_iter().find(|&x| x >= 5) +} + +fn plus_one(a: i32) -> Option<i32> { + Some(a + 1) +} +fn fn_instead_of_some(a: &[i32]) -> Option<i32> { + for &x in a { + if x == 1 { + return plus_one(x); + } + } + None +} + +fn for_in_condition(a: &[i32], b: bool) -> Option<i32> { + if b { + for &x in a { + if x == 1 { + return Some(x); + } + } + } + None +} + +fn intermediate_statements(a: &[i32]) -> Option<i32> { + for &x in a { + if x == 1 { + return Some(x); + } + } + + println!("side effect"); + + None +} + +fn mixed_binding_modes(arr: Vec<(i32, String)>) -> Option<i32> { + for (x, mut s) in arr { + if x == 1 && s.as_mut_str().len() == 2 { + return Some(x); + } + } + None +} + +fn as_closure() { + #[rustfmt::skip] + let f = |arr: Vec<i32>| -> Option<i32> { + arr.into_iter().find(|&x| x < 1) + }; +} + +fn in_block(a: &[i32]) -> Option<i32> { + let should_be_none = { + for &x in a { + if x == 1 { + return Some(x); + } + } + None + }; + + assert!(should_be_none.is_none()); + + should_be_none +} + +// Not handled yet +fn mut_binding(v: Vec<String>) -> Option<String> { + for mut s in v { + if s.as_mut_str().len() > 1 { + return Some(s); + } + } + None +} + +fn subpattern(v: Vec<[u32; 32]>) -> Option<[u32; 32]> { + for a @ [first, ..] in v { + if a[12] == first { + return Some(a); + } + } + None +} + +fn two_bindings(v: Vec<(u8, u8)>) -> Option<u8> { + for (a, n) in v { + if a == n { + return Some(a); + } + } + None +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs new file mode 100644 index 0000000000000..ed277ddaa722d --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs @@ -0,0 +1,242 @@ +// run-rustfix + +#![allow(unused, clippy::needless_return)] +#![warn(clippy::manual_find)] + +use std::collections::HashMap; + +const ARRAY: &[u32; 5] = &[2, 7, 1, 9, 3]; + +fn lookup(n: u32) -> Option<u32> { + for &v in ARRAY { + if v == n { + return Some(v); + } + } + None +} + +fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> { + for (a, _) in arr { + if a % 2 == 0 { + return Some(a); + } + } + None +} + +struct Data { + name: String, + is_true: bool, +} +fn with_struct(arr: Vec<Data>) -> Option<Data> { + for el in arr { + if el.name.len() == 10 { + return Some(el); + } + } + None +} + +struct Tuple(usize, usize); +fn with_tuple_struct(arr: Vec<Tuple>) -> Option<usize> { + for Tuple(a, _) in arr { + if a >= 3 { + return Some(a); + } + } + None +} + +struct A; +impl A { + fn should_keep(&self) -> bool { + true + } +} +fn with_method_call(arr: Vec<A>) -> Option<A> { + for el in arr { + if el.should_keep() { + return Some(el); + } + } + None +} + +fn with_closure(arr: Vec<u32>) -> Option<u32> { + let f = |el: u32| -> u32 { el + 10 }; + for el in arr { + if f(el) == 20 { + return Some(el); + } + } + None +} + +fn with_closure2(arr: HashMap<String, i32>) -> Option<i32> { + let f = |el: i32| -> bool { el == 10 }; + for &el in arr.values() { + if f(el) { + return Some(el); + } + } + None +} + +fn with_bool(arr: Vec<Data>) -> Option<Data> { + for el in arr { + if el.is_true { + return Some(el); + } + } + None +} + +fn with_side_effects(arr: Vec<u32>) -> Option<u32> { + for v in arr { + if v == 1 { + println!("side effect"); + return Some(v); + } + } + None +} + +fn with_else(arr: Vec<u32>) -> Option<u32> { + for el in arr { + if el % 2 == 0 { + return Some(el); + } else { + println!("{}", el); + } + } + None +} + +fn tuple_with_ref(v: [(u8, &u8); 3]) -> Option<u8> { + for (_, &x) in v { + if x > 10 { + return Some(x); + } + } + None +} + +fn ref_to_tuple_with_ref(v: &[(u8, &u8)]) -> Option<u8> { + for &(_, &x) in v { + if x > 10 { + return Some(x); + } + } + None +} + +fn explicit_ret(arr: Vec<i32>) -> Option<i32> { + for x in arr { + if x >= 5 { + return Some(x); + } + } + return None; +} + +fn plus_one(a: i32) -> Option<i32> { + Some(a + 1) +} +fn fn_instead_of_some(a: &[i32]) -> Option<i32> { + for &x in a { + if x == 1 { + return plus_one(x); + } + } + None +} + +fn for_in_condition(a: &[i32], b: bool) -> Option<i32> { + if b { + for &x in a { + if x == 1 { + return Some(x); + } + } + } + None +} + +fn intermediate_statements(a: &[i32]) -> Option<i32> { + for &x in a { + if x == 1 { + return Some(x); + } + } + + println!("side effect"); + + None +} + +fn mixed_binding_modes(arr: Vec<(i32, String)>) -> Option<i32> { + for (x, mut s) in arr { + if x == 1 && s.as_mut_str().len() == 2 { + return Some(x); + } + } + None +} + +fn as_closure() { + #[rustfmt::skip] + let f = |arr: Vec<i32>| -> Option<i32> { + for x in arr { + if x < 1 { + return Some(x); + } + } + None + }; +} + +fn in_block(a: &[i32]) -> Option<i32> { + let should_be_none = { + for &x in a { + if x == 1 { + return Some(x); + } + } + None + }; + + assert!(should_be_none.is_none()); + + should_be_none +} + +// Not handled yet +fn mut_binding(v: Vec<String>) -> Option<String> { + for mut s in v { + if s.as_mut_str().len() > 1 { + return Some(s); + } + } + None +} + +fn subpattern(v: Vec<[u32; 32]>) -> Option<[u32; 32]> { + for a @ [first, ..] in v { + if a[12] == first { + return Some(a); + } + } + None +} + +fn two_bindings(v: Vec<(u8, u8)>) -> Option<u8> { + for (a, n) in v { + if a == n { + return Some(a); + } + } + None +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.stderr b/src/tools/clippy/tests/ui/manual_find_fixable.stderr new file mode 100644 index 0000000000000..dbc4ff69a740b --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_find_fixable.stderr @@ -0,0 +1,142 @@ +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:11:5 + | +LL | / for &v in ARRAY { +LL | | if v == n { +LL | | return Some(v); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `ARRAY.iter().find(|&&v| v == n).copied()` + | + = note: `-D clippy::manual-find` implied by `-D warnings` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:20:5 + | +LL | / for (a, _) in arr { +LL | | if a % 2 == 0 { +LL | | return Some(a); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:33:5 + | +LL | / for el in arr { +LL | | if el.name.len() == 10 { +LL | | return Some(el); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().find(|el| el.name.len() == 10)` + | + = note: you may need to dereference some variables + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:43:5 + | +LL | / for Tuple(a, _) in arr { +LL | | if a >= 3 { +LL | | return Some(a); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().map(|Tuple(a, _)| a).find(|&a| a >= 3)` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:58:5 + | +LL | / for el in arr { +LL | | if el.should_keep() { +LL | | return Some(el); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().find(|el| el.should_keep())` + | + = note: you may need to dereference some variables + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:68:5 + | +LL | / for el in arr { +LL | | if f(el) == 20 { +LL | | return Some(el); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().find(|&el| f(el) == 20)` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:78:5 + | +LL | / for &el in arr.values() { +LL | | if f(el) { +LL | | return Some(el); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.values().find(|&&el| f(el)).copied()` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:87:5 + | +LL | / for el in arr { +LL | | if el.is_true { +LL | | return Some(el); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `arr.into_iter().find(|el| el.is_true)` + | + = note: you may need to dereference some variables + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:117:5 + | +LL | / for (_, &x) in v { +LL | | if x > 10 { +LL | | return Some(x); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `v.into_iter().map(|(_, &x)| x).find(|&x| x > 10)` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:126:5 + | +LL | / for &(_, &x) in v { +LL | | if x > 10 { +LL | | return Some(x); +LL | | } +LL | | } +LL | | None + | |________^ help: replace with an iterator: `v.iter().map(|&(_, &x)| x).find(|&x| x > 10)` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:135:5 + | +LL | / for x in arr { +LL | | if x >= 5 { +LL | | return Some(x); +LL | | } +LL | | } +LL | | return None; + | |________________^ help: replace with an iterator: `arr.into_iter().find(|&x| x >= 5)` + +error: manual implementation of `Iterator::find` + --> $DIR/manual_find_fixable.rs:190:9 + | +LL | / for x in arr { +LL | | if x < 1 { +LL | | return Some(x); +LL | | } +LL | | } +LL | | None + | |____________^ help: replace with an iterator: `arr.into_iter().find(|&x| x < 1)` + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs index f23c6d69b4c6a..03b2433f6666b 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![warn(clippy::manual_non_exhaustive)] #![allow(unused)] @@ -75,4 +76,12 @@ fn foo(x: &mut UsedHidden) { } } +#[expect(clippy::manual_non_exhaustive)] +enum ExpectLint { + A, + B, + #[doc(hidden)] + _C, +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr index 317a45d2cbd59..144fe86df554b 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr @@ -1,5 +1,5 @@ error: this seems like a manual implementation of the non-exhaustive pattern - --> $DIR/manual_non_exhaustive_enum.rs:4:1 + --> $DIR/manual_non_exhaustive_enum.rs:5:1 | LL | enum E { | ^----- @@ -15,13 +15,13 @@ LL | | } | = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` help: remove this variant - --> $DIR/manual_non_exhaustive_enum.rs:8:5 + --> $DIR/manual_non_exhaustive_enum.rs:9:5 | LL | _C, | ^^ error: this seems like a manual implementation of the non-exhaustive pattern - --> $DIR/manual_non_exhaustive_enum.rs:13:1 + --> $DIR/manual_non_exhaustive_enum.rs:14:1 | LL | / enum Ep { LL | | A, @@ -32,7 +32,7 @@ LL | | } | |_^ | help: remove this variant - --> $DIR/manual_non_exhaustive_enum.rs:17:5 + --> $DIR/manual_non_exhaustive_enum.rs:18:5 | LL | _C, | ^^ diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed new file mode 100644 index 0000000000000..5601c96c10b28 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed @@ -0,0 +1,55 @@ +// run-rustfix +// aux-build:macro_rules.rs + +#![warn(clippy::manual_rem_euclid)] + +#[macro_use] +extern crate macro_rules; + +macro_rules! internal_rem_euclid { + () => { + let value: i32 = 5; + let _: i32 = value.rem_euclid(4); + }; +} + +fn main() { + let value: i32 = 5; + + let _: i32 = value.rem_euclid(4); + let _: i32 = value.rem_euclid(4); + let _: i32 = value.rem_euclid(4); + let _: i32 = value.rem_euclid(4); + let _: i32 = 1 + value.rem_euclid(4); + + let _: i32 = (3 + value % 4) % 4; + let _: i32 = (-4 + value % -4) % -4; + let _: i32 = ((5 % 4) + 4) % 4; + + // Make sure the lint does not trigger if it would cause an error, like with an ambiguous + // integer type + let not_annotated = 24; + let _ = ((not_annotated % 4) + 4) % 4; + let inferred: _ = 24; + let _ = ((inferred % 4) + 4) % 4; + + // For lint to apply the constant must always be on the RHS of the previous value for % + let _: i32 = 4 % ((value % 4) + 4); + let _: i32 = ((4 % value) + 4) % 4; + + // Lint in internal macros + internal_rem_euclid!(); + + // Do not lint in external macros + manual_rem_euclid!(); +} + +// Should lint for params too +pub fn rem_euclid_4(num: i32) -> i32 { + num.rem_euclid(4) +} + +// Constant version came later, should still lint +pub const fn const_rem_euclid_4(num: i32) -> i32 { + num.rem_euclid(4) +} diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.rs b/src/tools/clippy/tests/ui/manual_rem_euclid.rs new file mode 100644 index 0000000000000..52135be26b73c --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.rs @@ -0,0 +1,55 @@ +// run-rustfix +// aux-build:macro_rules.rs + +#![warn(clippy::manual_rem_euclid)] + +#[macro_use] +extern crate macro_rules; + +macro_rules! internal_rem_euclid { + () => { + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + }; +} + +fn main() { + let value: i32 = 5; + + let _: i32 = ((value % 4) + 4) % 4; + let _: i32 = (4 + (value % 4)) % 4; + let _: i32 = (value % 4 + 4) % 4; + let _: i32 = (4 + value % 4) % 4; + let _: i32 = 1 + (4 + value % 4) % 4; + + let _: i32 = (3 + value % 4) % 4; + let _: i32 = (-4 + value % -4) % -4; + let _: i32 = ((5 % 4) + 4) % 4; + + // Make sure the lint does not trigger if it would cause an error, like with an ambiguous + // integer type + let not_annotated = 24; + let _ = ((not_annotated % 4) + 4) % 4; + let inferred: _ = 24; + let _ = ((inferred % 4) + 4) % 4; + + // For lint to apply the constant must always be on the RHS of the previous value for % + let _: i32 = 4 % ((value % 4) + 4); + let _: i32 = ((4 % value) + 4) % 4; + + // Lint in internal macros + internal_rem_euclid!(); + + // Do not lint in external macros + manual_rem_euclid!(); +} + +// Should lint for params too +pub fn rem_euclid_4(num: i32) -> i32 { + ((num % 4) + 4) % 4 +} + +// Constant version came later, should still lint +pub const fn const_rem_euclid_4(num: i32) -> i32 { + ((num % 4) + 4) % 4 +} diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr new file mode 100644 index 0000000000000..a237fd0213c1e --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr @@ -0,0 +1,57 @@ +error: manual `rem_euclid` implementation + --> $DIR/manual_rem_euclid.rs:19:18 + | +LL | let _: i32 = ((value % 4) + 4) % 4; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` + | + = note: `-D clippy::manual-rem-euclid` implied by `-D warnings` + +error: manual `rem_euclid` implementation + --> $DIR/manual_rem_euclid.rs:20: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:21: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:22: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:23: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:12: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) + +error: manual `rem_euclid` implementation + --> $DIR/manual_rem_euclid.rs:49:5 + | +LL | ((num % 4) + 4) % 4 + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)` + +error: manual `rem_euclid` implementation + --> $DIR/manual_rem_euclid.rs:54:5 + | +LL | ((num % 4) + 4) % 4 + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)` + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed new file mode 100644 index 0000000000000..fba503a20667a --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_retain.fixed @@ -0,0 +1,240 @@ +// run-rustfix +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_retain)] +#![allow(unused)] +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; + +fn main() { + binary_heap_retain(); + btree_set_retain(); + btree_map_retain(); + hash_set_retain(); + hash_map_retain(); + string_retain(); + vec_deque_retain(); + vec_retain(); + _msrv_153(); + _msrv_126(); + _msrv_118(); +} + +fn binary_heap_retain() { + // NOTE: Do not lint now, because binary_heap_retain is nighyly API. + // And we need to add a test case for msrv if we update this implmention. + // https://github.com/rust-lang/rust/issues/71503 + let mut heap = BinaryHeap::from([1, 2, 3]); + heap = heap.into_iter().filter(|x| x % 2 == 0).collect(); + heap = heap.iter().filter(|&x| x % 2 == 0).copied().collect(); + heap = heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); + + // Do not lint, because type conversion is performed + heap = heap.into_iter().filter(|x| x % 2 == 0).collect::<BinaryHeap<i8>>(); + heap = heap.iter().filter(|&x| x % 2 == 0).copied().collect::<BinaryHeap<i8>>(); + heap = heap.iter().filter(|&x| x % 2 == 0).cloned().collect::<BinaryHeap<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: BinaryHeap<i8> = heap.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: BinaryHeap<i8> = heap.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn btree_map_retain() { + let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + // Do lint. + btree_map.retain(|k, _| k % 2 == 0); + btree_map.retain(|_, &mut v| v % 2 == 0); + btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0)); + + // Do not lint. + btree_map = btree_map + .into_iter() + .filter(|(x, _)| x % 2 == 0) + .collect::<BTreeMap<i8, i8>>(); + + // Do not lint, because this expression is not assign. + let mut foobar: BTreeMap<i8, i8> = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + btree_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect(); +} + +fn btree_set_retain() { + let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]); + + // Do lint. + btree_set.retain(|x| x % 2 == 0); + btree_set.retain(|x| x % 2 == 0); + btree_set.retain(|x| x % 2 == 0); + + // Do not lint, because type conversion is performed + btree_set = btree_set + .iter() + .filter(|&x| x % 2 == 0) + .copied() + .collect::<BTreeSet<i8>>(); + + btree_set = btree_set + .iter() + .filter(|&x| x % 2 == 0) + .cloned() + .collect::<BTreeSet<i8>>(); + + btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect::<BTreeSet<i8>>(); + + // Do not lint, because this expression is not assign. + let mut foobar: BTreeSet<i8> = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut bar: BTreeSet<i8> = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn hash_map_retain() { + let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + // Do lint. + hash_map.retain(|k, _| k % 2 == 0); + hash_map.retain(|_, &mut v| v % 2 == 0); + hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0)); + + // Do not lint. + hash_map = hash_map + .into_iter() + .filter(|(x, _)| x % 2 == 0) + .collect::<HashMap<i8, i8>>(); + + // Do not lint, because this expression is not assign. + let mut foobar: HashMap<i8, i8> = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + hash_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect(); +} + +fn hash_set_retain() { + let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); + // Do lint. + hash_set.retain(|x| x % 2 == 0); + hash_set.retain(|x| x % 2 == 0); + hash_set.retain(|x| x % 2 == 0); + + // Do not lint, because type conversion is performed + hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::<HashSet<i8>>(); + hash_set = hash_set + .iter() + .filter(|&x| x % 2 == 0) + .copied() + .collect::<HashSet<i8>>(); + + hash_set = hash_set + .iter() + .filter(|&x| x % 2 == 0) + .cloned() + .collect::<HashSet<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: HashSet<i8> = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: HashSet<i8> = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|&x| x % 2 == 0).collect(); +} + +fn string_retain() { + let mut s = String::from("foobar"); + // Do lint. + s.retain(|c| c != 'o'); + + // Do not lint, because this expression is not assign. + let mut bar: String = s.chars().filter(|&c| c != 'o').to_owned().collect(); + + // Do not lint, because it is an assignment to a different variable. + s = bar.chars().filter(|&c| c != 'o').to_owned().collect(); +} + +fn vec_retain() { + let mut vec = vec![0, 1, 2]; + // Do lint. + vec.retain(|x| x % 2 == 0); + vec.retain(|x| x % 2 == 0); + vec.retain(|x| x % 2 == 0); + + // Do not lint, because type conversion is performed + vec = vec.into_iter().filter(|x| x % 2 == 0).collect::<Vec<i8>>(); + vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect::<Vec<i8>>(); + vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect::<Vec<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: Vec<i8> = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: Vec<i8> = vec.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn vec_deque_retain() { + let mut vec_deque = VecDeque::new(); + vec_deque.extend(1..5); + + // Do lint. + vec_deque.retain(|x| x % 2 == 0); + vec_deque.retain(|x| x % 2 == 0); + vec_deque.retain(|x| x % 2 == 0); + + // Do not lint, because type conversion is performed + vec_deque = vec_deque + .iter() + .filter(|&x| x % 2 == 0) + .copied() + .collect::<VecDeque<i8>>(); + vec_deque = vec_deque + .iter() + .filter(|&x| x % 2 == 0) + .cloned() + .collect::<VecDeque<i8>>(); + vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect::<VecDeque<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: VecDeque<i8> = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: VecDeque<i8> = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn _msrv_153() { + #![clippy::msrv = "1.52"] + let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + + let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]); + btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); +} + +fn _msrv_126() { + #![clippy::msrv = "1.25"] + let mut s = String::from("foobar"); + s = s.chars().filter(|&c| c != 'o').to_owned().collect(); +} + +fn _msrv_118() { + #![clippy::msrv = "1.17"] + let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); + hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); +} diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs new file mode 100644 index 0000000000000..81a849fe7684c --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_retain.rs @@ -0,0 +1,246 @@ +// run-rustfix +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_retain)] +#![allow(unused)] +use std::collections::BTreeMap; +use std::collections::BTreeSet; +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::collections::VecDeque; + +fn main() { + binary_heap_retain(); + btree_set_retain(); + btree_map_retain(); + hash_set_retain(); + hash_map_retain(); + string_retain(); + vec_deque_retain(); + vec_retain(); + _msrv_153(); + _msrv_126(); + _msrv_118(); +} + +fn binary_heap_retain() { + // NOTE: Do not lint now, because binary_heap_retain is nighyly API. + // And we need to add a test case for msrv if we update this implmention. + // https://github.com/rust-lang/rust/issues/71503 + let mut heap = BinaryHeap::from([1, 2, 3]); + heap = heap.into_iter().filter(|x| x % 2 == 0).collect(); + heap = heap.iter().filter(|&x| x % 2 == 0).copied().collect(); + heap = heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); + + // Do not lint, because type conversion is performed + heap = heap.into_iter().filter(|x| x % 2 == 0).collect::<BinaryHeap<i8>>(); + heap = heap.iter().filter(|&x| x % 2 == 0).copied().collect::<BinaryHeap<i8>>(); + heap = heap.iter().filter(|&x| x % 2 == 0).cloned().collect::<BinaryHeap<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: BinaryHeap<i8> = heap.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: BinaryHeap<i8> = heap.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn btree_map_retain() { + let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + // Do lint. + btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); + btree_map = btree_map + .into_iter() + .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) + .collect(); + + // Do not lint. + btree_map = btree_map + .into_iter() + .filter(|(x, _)| x % 2 == 0) + .collect::<BTreeMap<i8, i8>>(); + + // Do not lint, because this expression is not assign. + let mut foobar: BTreeMap<i8, i8> = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + btree_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect(); +} + +fn btree_set_retain() { + let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]); + + // Do lint. + btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); + btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because type conversion is performed + btree_set = btree_set + .iter() + .filter(|&x| x % 2 == 0) + .copied() + .collect::<BTreeSet<i8>>(); + + btree_set = btree_set + .iter() + .filter(|&x| x % 2 == 0) + .cloned() + .collect::<BTreeSet<i8>>(); + + btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect::<BTreeSet<i8>>(); + + // Do not lint, because this expression is not assign. + let mut foobar: BTreeSet<i8> = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut bar: BTreeSet<i8> = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn hash_map_retain() { + let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + // Do lint. + hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); + hash_map = hash_map + .into_iter() + .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) + .collect(); + + // Do not lint. + hash_map = hash_map + .into_iter() + .filter(|(x, _)| x % 2 == 0) + .collect::<HashMap<i8, i8>>(); + + // Do not lint, because this expression is not assign. + let mut foobar: HashMap<i8, i8> = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + hash_map = foobar.into_iter().filter(|(k, _)| k % 2 == 0).collect(); +} + +fn hash_set_retain() { + let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); + // Do lint. + hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); + + // Do not lint, because type conversion is performed + hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::<HashSet<i8>>(); + hash_set = hash_set + .iter() + .filter(|&x| x % 2 == 0) + .copied() + .collect::<HashSet<i8>>(); + + hash_set = hash_set + .iter() + .filter(|&x| x % 2 == 0) + .cloned() + .collect::<HashSet<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: HashSet<i8> = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: HashSet<i8> = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|&x| x % 2 == 0).collect(); +} + +fn string_retain() { + let mut s = String::from("foobar"); + // Do lint. + s = s.chars().filter(|&c| c != 'o').to_owned().collect(); + + // Do not lint, because this expression is not assign. + let mut bar: String = s.chars().filter(|&c| c != 'o').to_owned().collect(); + + // Do not lint, because it is an assignment to a different variable. + s = bar.chars().filter(|&c| c != 'o').to_owned().collect(); +} + +fn vec_retain() { + let mut vec = vec![0, 1, 2]; + // Do lint. + vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); + vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); + vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because type conversion is performed + vec = vec.into_iter().filter(|x| x % 2 == 0).collect::<Vec<i8>>(); + vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect::<Vec<i8>>(); + vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect::<Vec<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: Vec<i8> = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: Vec<i8> = vec.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn vec_deque_retain() { + let mut vec_deque = VecDeque::new(); + vec_deque.extend(1..5); + + // Do lint. + vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); + vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); + vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because type conversion is performed + vec_deque = vec_deque + .iter() + .filter(|&x| x % 2 == 0) + .copied() + .collect::<VecDeque<i8>>(); + vec_deque = vec_deque + .iter() + .filter(|&x| x % 2 == 0) + .cloned() + .collect::<VecDeque<i8>>(); + vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect::<VecDeque<i8>>(); + + // Do not lint, because this expression is not assign. + let mut bar: VecDeque<i8> = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); + let mut foobar: VecDeque<i8> = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); + + // Do not lint, because it is an assignment to a different variable. + bar = foobar.iter().filter(|&x| x % 2 == 0).copied().collect(); + bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect(); + bar = foobar.into_iter().filter(|x| x % 2 == 0).collect(); +} + +fn _msrv_153() { + #![clippy::msrv = "1.52"] + let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + + let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]); + btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); +} + +fn _msrv_126() { + #![clippy::msrv = "1.25"] + let mut s = String::from("foobar"); + s = s.chars().filter(|&c| c != 'o').to_owned().collect(); +} + +fn _msrv_118() { + #![clippy::msrv = "1.17"] + let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); + hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect(); + hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); +} diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr new file mode 100644 index 0000000000000..ec635919b48fb --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_retain.stderr @@ -0,0 +1,124 @@ +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:52:5 + | +LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)` + | + = note: `-D clippy::manual-retain` implied by `-D warnings` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:53:5 + | +LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:54:5 + | +LL | / btree_map = btree_map +LL | | .into_iter() +LL | | .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) +LL | | .collect(); + | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:76:5 + | +LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:77:5 + | +LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:78:5 + | +LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:108:5 + | +LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:109:5 + | +LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:110:5 + | +LL | / hash_map = hash_map +LL | | .into_iter() +LL | | .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) +LL | | .collect(); + | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:131:5 + | +LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:132:5 + | +LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:133:5 + | +LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:162:5 + | +LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:174:5 + | +LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:175:5 + | +LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:176:5 + | +LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:198:5 + | +LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:199:5 + | +LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` + +error: this expression can be written more simply using `.retain()` + --> $DIR/manual_retain.rs:200:5 + | +LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` + +error: aborting due to 19 previous errors + diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr index c9c60df838f67..4b2630d685847 100644 --- a/src/tools/clippy/tests/ui/map_flatten.stderr +++ b/src/tools/clippy/tests/ui/map_flatten.stderr @@ -12,14 +12,12 @@ LL | | .flatten(); | |__________________^ | = note: `-D clippy::map-flatten` implied by `-D warnings` -help: try replacing `map` with `and_then` +help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|x| { LL + if x <= 5 { LL + Some(x) - | -help: and remove the `.flatten()` - | +LL + } else { LL + None LL + } LL ~ }); @@ -38,14 +36,12 @@ LL | | }) LL | | .flatten(); | |__________________^ | -help: try replacing `map` with `and_then` +help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|x| { LL + if x == 1 { LL + Ok(x) - | -help: and remove the `.flatten()` - | +LL + } else { LL + Err(0) LL + } LL ~ }); @@ -64,14 +60,13 @@ LL | | }) LL | | .flatten(); | |__________________^ | -help: try replacing `map` with `and_then` +help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|res| { LL + if res > 0 { LL + do_something(); - | -help: and remove the `.flatten()` - | +LL + Ok(res) +LL + } else { LL + Err(0) LL + } LL ~ }); @@ -90,14 +85,12 @@ LL | | }) LL | | .flatten() | |__________________^ | -help: try replacing `map` with `filter_map` +help: try replacing `map` with `filter_map` and remove the `.flatten()` | LL ~ .filter_map(|some_value| { LL + if some_value > 3 { LL + Some(some_value) - | -help: and remove the `.flatten()` - | +LL + } else { LL + None LL + } LL + }) diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed index 928e5bd509c3f..e9b41354c58fa 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed @@ -59,8 +59,6 @@ fn issue8878() { .and_then(|_| { // we need some newlines // so that the span is big enough -// we need some newlines -// so that the span is big enough // for a splitted output of the diagnostic Some("") // whitespace beforehand is important as well diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr index 828e24acaad6c..f3b82ad08d0fc 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr @@ -2,79 +2,45 @@ error: called `map(..).flatten()` on `Iterator` --> $DIR/map_flatten_fixable.rs:18:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)` | = note: `-D clippy::map-flatten` implied by `-D warnings` -help: try replacing `map` with `filter_map`, and remove the `.flatten()` - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect(); - | ~~~~~~~~~~~~~~~~~~~~~ error: called `map(..).flatten()` on `Iterator` --> $DIR/map_flatten_fixable.rs:19:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try replacing `map` with `filter_map`, and remove the `.flatten()` - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` --> $DIR/map_flatten_fixable.rs:20:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try replacing `map` with `filter_map`, and remove the `.flatten()` - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` --> $DIR/map_flatten_fixable.rs:21:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try replacing `map` with `filter_map`, and remove the `.flatten()` - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` --> $DIR/map_flatten_fixable.rs:24:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try replacing `map` with `flat_map`, and remove the `.flatten()` - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); - | ~~~~~~~~~~~~~~~~~~ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` --> $DIR/map_flatten_fixable.rs:27:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); - | ^^^^^^^^^^^^^^^^^^^^ - | -help: try replacing `map` with `and_then`, and remove the `.flatten()` - | -LL | let _: Option<_> = (Some(Some(1))).and_then(|x| x); - | ~~~~~~~~~~~~~~~ + | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` --> $DIR/map_flatten_fixable.rs:30:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); - | ^^^^^^^^^^^^^^^^^^^^ - | -help: try replacing `map` with `and_then`, and remove the `.flatten()` - | -LL | let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x); - | ~~~~~~~~~~~~~~~ + | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Option` --> $DIR/map_flatten_fixable.rs:59:10 @@ -89,14 +55,12 @@ LL | | }) LL | | .flatten(); | |__________________^ | -help: try replacing `map` with `and_then` +help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|_| { LL + // we need some newlines LL + // so that the span is big enough - | -help: and remove the `.flatten()` - | +LL + // for a splitted output of the diagnostic LL + Some("") LL + // whitespace beforehand is important as well LL ~ }); diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index 9805097084d30..1970c2eae5314 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -15,6 +15,7 @@ clippy::use_self, clippy::useless_format, clippy::wrong_self_convention, + clippy::unused_async, clippy::unused_self, unused )] diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr index 6be38b24fbda2..b63672dd6fdbb 100644 --- a/src/tools/clippy/tests/ui/methods.stderr +++ b/src/tools/clippy/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:103:5 + --> $DIR/methods.rs:104:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:124:13 + --> $DIR/methods.rs:125:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_attr.rs index f83c3e0e281ca..44e407bd1ab2b 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_attr.rs +++ b/src/tools/clippy/tests/ui/min_rust_version_attr.rs @@ -155,6 +155,11 @@ fn cast_abs_to_unsigned() { assert_eq!(10u32, x.abs() as u32); } +fn manual_rem_euclid() { + let x: i32 = 10; + let _: i32 = ((x % 4) + 4) % 4; +} + fn main() { filter_map_next(); checked_conversion(); @@ -174,6 +179,7 @@ fn main() { int_from_bool(); err_expect(); cast_abs_to_unsigned(); + manual_rem_euclid(); } mod just_under_msrv { @@ -211,3 +217,12 @@ mod just_above_msrv { } } } + +mod const_rem_euclid { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.50.0"] + + pub const fn const_rem_euclid_4(num: i32) -> i32 { + ((num % 4) + 4) % 4 + } +} diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr index de225eb740d03..b1c23b539ffde 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr +++ b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr @@ -1,12 +1,12 @@ error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:198:24 + --> $DIR/min_rust_version_attr.rs:204:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-strip` implied by `-D warnings` note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:197:9 + --> $DIR/min_rust_version_attr.rs:203:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,13 +17,13 @@ LL ~ assert_eq!(<stripped>.to_uppercase(), "WORLD!"); | error: stripping a prefix manually - --> $DIR/min_rust_version_attr.rs:210:24 + --> $DIR/min_rust_version_attr.rs:216:24 | LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); | ^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> $DIR/min_rust_version_attr.rs:209:9 + --> $DIR/min_rust_version_attr.rs:215:9 | LL | if s.starts_with("hello, ") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index e7a483c058295..cb00512243601 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -62,7 +62,18 @@ fn main() { 0 => &mut x, _ => &mut *x, }; - + let y: &mut i32 = match 0 { + // Lint here. The type given above triggers auto-borrow. + 0 => x, + _ => &mut *x, + }; + fn ref_mut_i32(_: &mut i32) {} + ref_mut_i32(match 0 { + // Lint here. The type given above triggers auto-borrow. + 0 => x, + _ => &mut *x, + }); + // use 'x' after to make sure it's still usable in the fixed code. *x = 5; let s = String::new(); @@ -74,6 +85,36 @@ fn main() { let _ = x.0; let x = &x as *const (i32, i32); let _ = unsafe { (*x).0 }; + + // Issue #8367 + trait Foo { + fn foo(self); + } + impl Foo for &'_ () { + fn foo(self) {} + } + (&()).foo(); // Don't lint. `()` doesn't implement `Foo` + (&()).foo(); + + impl Foo for i32 { + fn foo(self) {} + } + impl Foo for &'_ i32 { + fn foo(self) {} + } + (&5).foo(); // Don't lint. `5` will call `<i32 as Foo>::foo` + (&5).foo(); + + trait FooRef { + fn foo_ref(&self); + } + impl FooRef for () { + fn foo_ref(&self) {} + } + impl FooRef for &'_ () { + fn foo_ref(&self) {} + } + (&&()).foo_ref(); // Don't lint. `&()` will call `<() as FooRef>::foo_ref` } #[allow(clippy::needless_borrowed_reference)] diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 1d6bf46405a2f..d636a40100378 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -62,7 +62,18 @@ fn main() { 0 => &mut x, _ => &mut *x, }; - + let y: &mut i32 = match 0 { + // Lint here. The type given above triggers auto-borrow. + 0 => &mut x, + _ => &mut *x, + }; + fn ref_mut_i32(_: &mut i32) {} + ref_mut_i32(match 0 { + // Lint here. The type given above triggers auto-borrow. + 0 => &mut x, + _ => &mut *x, + }); + // use 'x' after to make sure it's still usable in the fixed code. *x = 5; let s = String::new(); @@ -74,6 +85,36 @@ fn main() { let _ = (&x).0; let x = &x as *const (i32, i32); let _ = unsafe { (&*x).0 }; + + // Issue #8367 + trait Foo { + fn foo(self); + } + impl Foo for &'_ () { + fn foo(self) {} + } + (&()).foo(); // Don't lint. `()` doesn't implement `Foo` + (&&()).foo(); + + impl Foo for i32 { + fn foo(self) {} + } + impl Foo for &'_ i32 { + fn foo(self) {} + } + (&5).foo(); // Don't lint. `5` will call `<i32 as Foo>::foo` + (&&5).foo(); + + trait FooRef { + fn foo_ref(&self); + } + impl FooRef for () { + fn foo_ref(&self) {} + } + impl FooRef for &'_ () { + fn foo_ref(&self) {} + } + (&&()).foo_ref(); // Don't lint. `&()` will call `<() as FooRef>::foo_ref` } #[allow(clippy::needless_borrowed_reference)] diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index be59d8f546d23..8a2e2b9895908 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -84,17 +84,41 @@ error: this expression creates a reference which is immediately dereferenced by LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:67:14 + | +LL | 0 => &mut x, + | ^^^^^^ help: change this to: `x` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:73:14 + | +LL | 0 => &mut x, + | ^^^^^^ help: change this to: `x` + error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:74:13 + --> $DIR/needless_borrow.rs:85:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:76:22 + --> $DIR/needless_borrow.rs:87:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` -error: aborting due to 16 previous errors +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:97:5 + | +LL | (&&()).foo(); + | ^^^^^^ help: change this to: `(&())` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:106:5 + | +LL | (&&5).foo(); + | ^^^^^ help: change this to: `(&5)` + +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs index 04b6283da3c3b..222e8e617995d 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.rs +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs @@ -1,7 +1,7 @@ // FIXME: run-rustfix waiting on multi-span suggestions #![warn(clippy::needless_borrow)] -#![allow(clippy::needless_borrowed_reference)] +#![allow(clippy::needless_borrowed_reference, clippy::explicit_auto_deref)] fn f1(_: &str) {} macro_rules! m1 { diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index fee8e3030b808..4c98e1827bdbb 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -1,5 +1,4 @@ // run-rustfix -#![feature(let_chains)] #![allow( unused, clippy::assign_op_pattern, diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index 402d9f9ef7f81..25e1e0214fb44 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -1,5 +1,4 @@ // run-rustfix -#![feature(let_chains)] #![allow( unused, clippy::assign_op_pattern, diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index 313cdbbeba183..97f0f7019a9df 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:23:5 + --> $DIR/needless_late_init.rs:22:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:26:5 + --> $DIR/needless_late_init.rs:25:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:27:5 + --> $DIR/needless_late_init.rs:26:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:31:5 + --> $DIR/needless_late_init.rs:30: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:34:5 + --> $DIR/needless_late_init.rs:33:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:39:5 + --> $DIR/needless_late_init.rs:38:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:48:5 + --> $DIR/needless_late_init.rs:47:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:55:5 + --> $DIR/needless_late_init.rs:54:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:63:5 + --> $DIR/needless_late_init.rs:62:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:70:5 + --> $DIR/needless_late_init.rs:69:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:76:5 + --> $DIR/needless_late_init.rs:75:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:84:5 + --> $DIR/needless_late_init.rs:83:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:88:5 + --> $DIR/needless_late_init.rs:87:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:92:5 + --> $DIR/needless_late_init.rs:91:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:111:5 + --> $DIR/needless_late_init.rs:110:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:128:5 + --> $DIR/needless_late_init.rs:127:5 | LL | let a; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr index d960c86a9f0ef..38f33c53f128b 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr @@ -124,7 +124,7 @@ help: consider marking this type as `Copy` --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:131:29 @@ -136,7 +136,7 @@ help: consider marking this type as `Copy` --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:131:45 @@ -148,7 +148,7 @@ help: consider marking this type as `Copy` --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:131:61 @@ -160,7 +160,7 @@ help: consider marking this type as `Copy` --> $DIR/needless_pass_by_value.rs:123:1 | LL | struct CopyWrapper(u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:143:40 diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index 7c828430b7853..0bc0d0011efe0 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![feature(lint_reasons)] #![feature(let_else)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ )] #![warn(clippy::needless_return)] +use std::cell::RefCell; + macro_rules! the_answer { () => { 42 @@ -86,17 +89,15 @@ fn test_nested_match(x: u32) { } } -fn read_line() -> String { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - return stdin.lock().lines().next().unwrap().unwrap(); +fn temporary_outlives_local() -> String { + let x = RefCell::<String>::default(); + return x.borrow().clone(); } fn borrows_but_not_last(value: bool) -> String { if value { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - let _a = stdin.lock().lines().next().unwrap().unwrap(); + let x = RefCell::<String>::default(); + let _a = x.borrow().clone(); String::from("test") } else { String::new() @@ -197,17 +198,15 @@ async fn async_test_void_match(x: u32) { } } -async fn async_read_line() -> String { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - return stdin.lock().lines().next().unwrap().unwrap(); +async fn async_temporary_outlives_local() -> String { + let x = RefCell::<String>::default(); + return x.borrow().clone(); } async fn async_borrows_but_not_last(value: bool) -> String { if value { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - let _a = stdin.lock().lines().next().unwrap().unwrap(); + let x = RefCell::<String>::default(); + let _a = x.borrow().clone(); String::from("test") } else { String::new() @@ -229,4 +228,13 @@ fn needless_return_macro() -> String { format!("Hello {}", "world!") } +fn check_expect() -> bool { + if true { + // no error! + return true; + } + #[expect(clippy::needless_return)] + return true; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index fe82af00e6750..eb9f72e8e7822 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -1,5 +1,6 @@ // run-rustfix +#![feature(lint_reasons)] #![feature(let_else)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ )] #![warn(clippy::needless_return)] +use std::cell::RefCell; + macro_rules! the_answer { () => { 42 @@ -86,17 +89,15 @@ fn test_nested_match(x: u32) { } } -fn read_line() -> String { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - return stdin.lock().lines().next().unwrap().unwrap(); +fn temporary_outlives_local() -> String { + let x = RefCell::<String>::default(); + return x.borrow().clone(); } fn borrows_but_not_last(value: bool) -> String { if value { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - let _a = stdin.lock().lines().next().unwrap().unwrap(); + let x = RefCell::<String>::default(); + let _a = x.borrow().clone(); return String::from("test"); } else { return String::new(); @@ -197,17 +198,15 @@ async fn async_test_void_match(x: u32) { } } -async fn async_read_line() -> String { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - return stdin.lock().lines().next().unwrap().unwrap(); +async fn async_temporary_outlives_local() -> String { + let x = RefCell::<String>::default(); + return x.borrow().clone(); } async fn async_borrows_but_not_last(value: bool) -> String { if value { - use std::io::BufRead; - let stdin = ::std::io::stdin(); - let _a = stdin.lock().lines().next().unwrap().unwrap(); + let x = RefCell::<String>::default(); + let _a = x.borrow().clone(); return String::from("test"); } else { return String::new(); @@ -229,4 +228,13 @@ fn needless_return_macro() -> String { return format!("Hello {}", "world!"); } +fn check_expect() -> bool { + if true { + // no error! + return true; + } + #[expect(clippy::needless_return)] + return true; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 4c8be47b025e2..83ff07638693c 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:24:5 + --> $DIR/needless_return.rs:27:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` @@ -7,217 +7,217 @@ LL | return true; = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded `return` statement - --> $DIR/needless_return.rs:28:5 + --> $DIR/needless_return.rs:31:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:33:9 + --> $DIR/needless_return.rs:36:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:35:9 + --> $DIR/needless_return.rs:38:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:41:17 + --> $DIR/needless_return.rs:44:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:43:13 + --> $DIR/needless_return.rs:46:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:50:9 + --> $DIR/needless_return.rs:53:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:52:16 + --> $DIR/needless_return.rs:55:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:56:5 + --> $DIR/needless_return.rs:59:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()` error: unneeded `return` statement - --> $DIR/needless_return.rs:60:5 + --> $DIR/needless_return.rs:63:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:65:9 + --> $DIR/needless_return.rs:68:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:67:9 + --> $DIR/needless_return.rs:70:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:74:14 + --> $DIR/needless_return.rs:77:14 | LL | _ => return, | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:83:13 + --> $DIR/needless_return.rs:86:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:85:14 + --> $DIR/needless_return.rs:88:14 | LL | _ => return, | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:100:9 + --> $DIR/needless_return.rs:101:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:102:9 + --> $DIR/needless_return.rs:103:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:124:32 + --> $DIR/needless_return.rs:125:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:129:13 + --> $DIR/needless_return.rs:130:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:131:20 + --> $DIR/needless_return.rs:132:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:137:32 + --> $DIR/needless_return.rs:138:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:146:5 + --> $DIR/needless_return.rs:147:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:150:5 + --> $DIR/needless_return.rs:151:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:155:9 + --> $DIR/needless_return.rs:156:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:157:9 + --> $DIR/needless_return.rs:158:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:163:17 + --> $DIR/needless_return.rs:164:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:165:13 + --> $DIR/needless_return.rs:166:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:172:9 + --> $DIR/needless_return.rs:173:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:174:16 + --> $DIR/needless_return.rs:175:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:178:5 + --> $DIR/needless_return.rs:179:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()` error: unneeded `return` statement - --> $DIR/needless_return.rs:182:5 + --> $DIR/needless_return.rs:183:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:187:9 + --> $DIR/needless_return.rs:188:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:189:9 + --> $DIR/needless_return.rs:190:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:196:14 + --> $DIR/needless_return.rs:197:14 | LL | _ => return, | ^^^^^^ help: replace `return` with a unit value: `()` error: unneeded `return` statement - --> $DIR/needless_return.rs:211:9 + --> $DIR/needless_return.rs:210:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:213:9 + --> $DIR/needless_return.rs:212:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:229:5 + --> $DIR/needless_return.rs:228:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `format!("Hello {}", "world!")` diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed index 35af9d6ae317f..58ab9e8567838 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.fixed +++ b/src/tools/clippy/tests/ui/neg_multiply.fixed @@ -38,6 +38,9 @@ fn main() { 0xcafe | -0xff00; + -(3_usize as i32); + -(3_usize as i32); + -1 * -1; // should be ok X * -1; // should be ok diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs index 7dbdb0906ceeb..581290dc72e43 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.rs +++ b/src/tools/clippy/tests/ui/neg_multiply.rs @@ -38,6 +38,9 @@ fn main() { 0xcafe | 0xff00 * -1; + 3_usize as i32 * -1; + (3_usize as i32) * -1; + -1 * -1; // should be ok X * -1; // should be ok diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr index dbf8fb36938cb..388ef29eb8567 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.stderr +++ b/src/tools/clippy/tests/ui/neg_multiply.stderr @@ -36,5 +36,17 @@ error: this multiplication by -1 can be written more succinctly LL | 0xcafe | 0xff00 * -1; | ^^^^^^^^^^^ help: consider using: `-0xff00` -error: aborting due to 6 previous errors +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:41:5 + | +LL | 3_usize as i32 * -1; + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)` + +error: this multiplication by -1 can be written more succinctly + --> $DIR/neg_multiply.rs:42:5 + | +LL | (3_usize as i32) * -1; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index 7ece66a1ccb6f..f0c59b4080be3 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -4,7 +4,7 @@ #![allow(path_statements)] #![allow(clippy::deref_addrof)] #![allow(clippy::redundant_field_names)] -#![feature(untagged_unions)] + struct Unit; struct Tuple(i32); diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs index fa5743c115577..24ae62bb05884 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] @@ -50,3 +51,9 @@ fn issue4548() { if i != j && f(i, j) != 0 || i == j && f(i, j) != 1 {} } + +fn check_expect() { + let a: bool = unimplemented!(); + #[expect(clippy::nonminimal_bool)] + let _ = !!a; +} diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr index bb93cbbd5e190..fc6a5ce1dc2ee 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:10:13 + --> $DIR/nonminimal_bool.rs:11:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -7,43 +7,43 @@ LL | let _ = !true; = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:11:13 + --> $DIR/nonminimal_bool.rs:12:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:12:13 + --> $DIR/nonminimal_bool.rs:13:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:13:13 + --> $DIR/nonminimal_bool.rs:14:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:17:13 + --> $DIR/nonminimal_bool.rs:18:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `a || !b` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:18:13 + --> $DIR/nonminimal_bool.rs:19:13 | LL | let _ = !(!a || b); | ^^^^^^^^^^ help: try: `a && !b` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:19:13 + --> $DIR/nonminimal_bool.rs:20:13 | LL | let _ = !a && !(b && c); | ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:27:13 + --> $DIR/nonminimal_bool.rs:28:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:28:13 + --> $DIR/nonminimal_bool.rs:29:13 | LL | let _ = a == b || c == 5 || a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | let _ = a == b || c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:29:13 + --> $DIR/nonminimal_bool.rs:30:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:30:13 + --> $DIR/nonminimal_bool.rs:31:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | let _ = a != b || c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:31:13 + --> $DIR/nonminimal_bool.rs:32:13 | LL | let _ = a != b && !(a != b && c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 3208048e0d53c..123aed40251e2 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -185,8 +185,7 @@ mod issue8239 { .reduce(|mut acc, f| { acc.push_str(&f); acc - }) - .unwrap_or_default(); + }).unwrap_or_default(); } fn more_to_max_suggestion_highest_lines_1() { @@ -198,8 +197,7 @@ mod issue8239 { let _ = ""; acc.push_str(&f); acc - }) - .unwrap_or_default(); + }).unwrap_or_default(); } fn equal_to_max_suggestion_highest_lines() { diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 549b00ae3c459..dfe15654bc32c 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -109,16 +109,50 @@ LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:189:14 + --> $DIR/or_fun_call.rs:182:9 + | +LL | / frames +LL | | .iter() +LL | | .map(|f: &String| f.to_lowercase()) +LL | | .reduce(|mut acc, f| { +... | +LL | | }) +LL | | .unwrap_or(String::new()); + | |_____________________________________^ + | +help: try this + | +LL ~ frames +LL + .iter() +LL + .map(|f: &String| f.to_lowercase()) +LL + .reduce(|mut acc, f| { +LL + acc.push_str(&f); +LL + acc +LL ~ }).unwrap_or_default(); | -LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:202:14 + --> $DIR/or_fun_call.rs:195:9 + | +LL | / iter.map(|f: &String| f.to_lowercase()) +LL | | .reduce(|mut acc, f| { +LL | | let _ = ""; +LL | | let _ = ""; +... | +LL | | }) +LL | | .unwrap_or(String::new()); + | |_____________________________________^ + | +help: try this + | +LL ~ iter.map(|f: &String| f.to_lowercase()) +LL + .reduce(|mut acc, f| { +LL + let _ = ""; +LL + let _ = ""; +LL + acc.push_str(&f); +LL + acc +LL ~ }).unwrap_or_default(); | -LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:208:9 diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 814bbc7af713b..fd15001e540c6 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -1,3 +1,4 @@ +#![feature(lint_reasons)] #![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] #![warn(clippy::ptr_arg)] @@ -109,9 +110,12 @@ mod issue_5644 { #[allow(clippy::ptr_arg)] _s: &String, #[allow(clippy::ptr_arg)] _p: &PathBuf, #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>, ) { } + fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {} + struct S; impl S { fn allowed( @@ -119,6 +123,7 @@ mod issue_5644 { #[allow(clippy::ptr_arg)] _s: &String, #[allow(clippy::ptr_arg)] _p: &PathBuf, #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>, ) { } } @@ -129,6 +134,7 @@ mod issue_5644 { #[allow(clippy::ptr_arg)] _s: &String, #[allow(clippy::ptr_arg)] _p: &PathBuf, #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + #[expect(clippy::ptr_arg)] _expect: &Cow<[i32]>, ) { } } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 7ec4a566ff34b..d64b5f454a5aa 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:7:14 + --> $DIR/ptr_arg.rs:8:14 | LL | fn do_vec(x: &Vec<i64>) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -7,43 +7,43 @@ LL | fn do_vec(x: &Vec<i64>) { = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:11:18 + --> $DIR/ptr_arg.rs:12:18 | LL | fn do_vec_mut(x: &mut Vec<i64>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:15:14 + --> $DIR/ptr_arg.rs:16:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:19:18 + --> $DIR/ptr_arg.rs:20:18 | LL | fn do_str_mut(x: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:23:15 + --> $DIR/ptr_arg.rs:24:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:27:19 + --> $DIR/ptr_arg.rs:28:19 | LL | fn do_path_mut(x: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:35:18 + --> $DIR/ptr_arg.rs:36:18 | LL | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:48:14 + --> $DIR/ptr_arg.rs:49:14 | LL | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ @@ -60,7 +60,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:57:18 + --> $DIR/ptr_arg.rs:58:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -76,7 +76,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:65:19 + --> $DIR/ptr_arg.rs:66:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -92,7 +92,7 @@ LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:73:44 + --> $DIR/ptr_arg.rs:74:44 | LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ @@ -106,13 +106,19 @@ LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:87:25 + --> $DIR/ptr_arg.rs:88:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` +error: writing `&String` instead of `&str` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:117:66 + | +LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {} + | ^^^^^^^ help: change this to: `&str` + error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:140:21 + --> $DIR/ptr_arg.rs:146:21 | LL | fn foo_vec(vec: &Vec<u8>) { | ^^^^^^^^ @@ -125,7 +131,7 @@ LL ~ let _ = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:145:23 + --> $DIR/ptr_arg.rs:151:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -138,7 +144,7 @@ LL ~ let _ = path.to_path_buf().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:150:21 + --> $DIR/ptr_arg.rs:156:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -151,10 +157,10 @@ LL ~ let _ = str.to_path_buf().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:156:29 + --> $DIR/ptr_arg.rs:162:29 | LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` -error: aborting due to 16 previous errors +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index 1525f6a93dfdd..da52c0acf93b0 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -1,6 +1,7 @@ // run-rustfix // rustfix-only-machine-applicable +#![feature(lint_reasons)] #![allow(clippy::implicit_clone, clippy::drop_non_drop)] use std::ffi::OsString; use std::path::Path; @@ -29,6 +30,10 @@ fn main() { #[allow(clippy::redundant_clone)] let _s = String::new().to_string(); + // Check that lint level works + #[expect(clippy::redundant_clone)] + let _s = String::new().to_string(); + let tup = (String::from("foo"),); let _t = tup.0; diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs index 2f82aefd92830..5867d019dbb7d 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.rs +++ b/src/tools/clippy/tests/ui/redundant_clone.rs @@ -1,6 +1,7 @@ // run-rustfix // rustfix-only-machine-applicable +#![feature(lint_reasons)] #![allow(clippy::implicit_clone, clippy::drop_non_drop)] use std::ffi::OsString; use std::path::Path; @@ -29,6 +30,10 @@ fn main() { #[allow(clippy::redundant_clone)] let _s = String::new().to_string(); + // Check that lint level works + #[expect(clippy::redundant_clone)] + let _s = String::new().to_string(); + let tup = (String::from("foo"),); let _t = tup.0.clone(); diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index 9f59017b26199..aa1dd7cbb45cd 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -1,180 +1,180 @@ error: redundant clone - --> $DIR/redundant_clone.rs:9:42 + --> $DIR/redundant_clone.rs:10:42 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use - --> $DIR/redundant_clone.rs:9:14 + --> $DIR/redundant_clone.rs:10:14 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:12:15 + --> $DIR/redundant_clone.rs:13:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:12:14 + --> $DIR/redundant_clone.rs:13:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:15:15 + --> $DIR/redundant_clone.rs:16:15 | LL | let _s = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:15:14 + --> $DIR/redundant_clone.rs:16:14 | LL | let _s = s.to_string(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:18:15 + --> $DIR/redundant_clone.rs:19:15 | LL | let _s = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:18:14 + --> $DIR/redundant_clone.rs:19:14 | LL | let _s = s.to_owned(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:20:42 + --> $DIR/redundant_clone.rs:21:42 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:20:14 + --> $DIR/redundant_clone.rs:21:14 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:22:42 + --> $DIR/redundant_clone.rs:23:42 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:22:14 + --> $DIR/redundant_clone.rs:23:14 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:24:29 + --> $DIR/redundant_clone.rs:25:29 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:24:14 + --> $DIR/redundant_clone.rs:25:14 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:26:29 + --> $DIR/redundant_clone.rs:27:29 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:26:14 + --> $DIR/redundant_clone.rs:27:14 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:33:19 + --> $DIR/redundant_clone.rs:38:19 | LL | let _t = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:33:14 + --> $DIR/redundant_clone.rs:38:14 | LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:65:25 + --> $DIR/redundant_clone.rs:70:25 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:65:24 + --> $DIR/redundant_clone.rs:70:24 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^ error: redundant clone - --> $DIR/redundant_clone.rs:122:15 + --> $DIR/redundant_clone.rs:127:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:122:14 + --> $DIR/redundant_clone.rs:127:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:123:15 + --> $DIR/redundant_clone.rs:128:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:123:14 + --> $DIR/redundant_clone.rs:128:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:133:19 + --> $DIR/redundant_clone.rs:138:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:133:18 + --> $DIR/redundant_clone.rs:138:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:145:14 + --> $DIR/redundant_clone.rs:150:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> $DIR/redundant_clone.rs:145:13 + --> $DIR/redundant_clone.rs:150:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:199:11 + --> $DIR/redundant_clone.rs:204:11 | LL | foo(&x.clone(), move || { | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:199:10 + --> $DIR/redundant_clone.rs:204:10 | LL | foo(&x.clone(), move || { | ^ diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs index 570ef406e4a99..c8d0e56b197f4 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -2,7 +2,7 @@ #![feature(lint_reasons)] #![warn(clippy::ref_binding_to_reference)] -#![allow(clippy::needless_borrowed_reference)] +#![allow(clippy::needless_borrowed_reference, clippy::explicit_auto_deref)] fn f1(_: &str) {} macro_rules! m2 { diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed index 6831fb2cf59e0..5190c5304c75d 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code)] +#![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] fn main() { diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs index 767518ab0c0f5..310d87333a93c 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code)] +#![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] fn main() { diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed index 7c940a2b069e4..5a2aee465d1bd 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code)] +#![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] fn main() { diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs index 77fd52e4ce769..0e98ae18a217c 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(dead_code)] +#![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] fn main() { diff --git a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs index 1ccb0a1d167d2..50999c6f2198b 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs @@ -8,7 +8,8 @@ clippy::missing_safety_doc, clippy::wrong_self_convention, clippy::missing_panics_doc, - clippy::return_self_not_must_use + clippy::return_self_not_must_use, + clippy::unused_async )] use std::ops::Mul; diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index 4347610f393f3..185e5009b60f1 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -64,6 +64,19 @@ fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() { }; } +fn should_not_trigger_lint_with_mutex_guard_in_match_scrutinee_when_lint_allowed() { + let mutex = Mutex::new(State {}); + + // Lint should not be triggered because it is "allowed" below. + #[allow(clippy::significant_drop_in_scrutinee)] + match mutex.lock().unwrap().foo() { + true => { + mutex.lock().unwrap().bar(); + }, + false => {}, + }; +} + fn should_not_trigger_lint_for_insignificant_drop() { // Should not trigger lint because there are no temporaries whose drops have a significant // side effect. @@ -591,4 +604,20 @@ fn should_trigger_lint_for_read_write_lock_for_loop() { } } +fn do_bar(mutex: &Mutex<State>) { + mutex.lock().unwrap().bar(); +} + +fn should_trigger_lint_without_significant_drop_in_arm() { + let mutex = Mutex::new(State {}); + + // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it + // is preserved until the end of the match, but there is no clear indication that this is the + // case. + match mutex.lock().unwrap().foo() { + true => do_bar(&mutex), + false => {}, + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index 5ce9520441637..88ea6bce25b6b 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -1,174 +1,290 @@ -error: temporary with significant drop in match scrutinee +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression --> $DIR/significant_drop_in_scrutinee.rs:59:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | true => { +LL | mutex.lock().unwrap().bar(); + | --------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here | = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings` + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex.lock().unwrap().foo(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:132:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:145:11 | LL | match s.lock_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | println!("{}", s.lock_m().get_the_value()); + | ---------- another value with significant `Drop` created here +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = s.lock_m().get_the_value(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:153:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:166:11 | LL | match s.lock_m_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | println!("{}", s.lock_m().get_the_value()); + | ---------- another value with significant `Drop` created here +... +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = s.lock_m_m().get_the_value(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:201:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:214:11 | LL | match counter.temp_increment().len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | }; + | - temporary lives until here | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = counter.temp_increment().len(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:224:16 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:237:16 | LL | match (mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex1.lock().unwrap().s.len(); LL ~ match (value, true) { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:233:22 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:246:22 | LL | match (true, mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex1.lock().unwrap().s.len(); LL ~ match (true, value, true) { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:243:16 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:256:16 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex1.lock().unwrap().s.len(); LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:243:54 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:256:54 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex2.lock().unwrap().s.len(); LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:254:15 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:267:15 | LL | match mutex3.lock().unwrap().s.as_str() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:264:22 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:277:22 | LL | match (true, mutex3.lock().unwrap().s.as_str()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:283:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:296:11 | LL | match mutex.lock().unwrap().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | true => { +LL | mutex.lock().unwrap().s.len(); + | --------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex.lock().unwrap().s.len() > 1; LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:290:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:303:11 | LL | match 1 < mutex.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | true => { +LL | mutex.lock().unwrap().s.len(); + | --------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = 1 < mutex.lock().unwrap().s.len(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:308:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:321:11 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | mutex1.lock().unwrap().s.len(), + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len() + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:319:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:332:11 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +... +LL | mutex1.lock().unwrap().s.len(), + | ---------------------- another value with significant `Drop` created here +LL | mutex2.lock().unwrap().s.len() + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:354:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:367:11 | LL | match get_mutex_guard().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | true => { +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = get_mutex_guard().s.len() > 1; LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:371:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:384:11 | LL | match match i { | ___________^ @@ -179,7 +295,14 @@ LL | | .s LL | | .len() LL | | > 1 | |___________^ - | +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = match i { @@ -192,8 +315,8 @@ LL + > 1; LL ~ match value | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:397:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:410:11 | LL | match if i > 1 { | ___________^ @@ -204,7 +327,14 @@ LL | | mutex2.lock().unwrap() LL | | .len() LL | | > 1 | |___________^ - | +... +LL | mutex1.lock().unwrap().s.len(); + | ---------------------- another value with significant `Drop` created here +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ let value = if i > 1 { @@ -218,83 +348,150 @@ LL + > 1; LL ~ match value | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:451:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:464:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | 0 | 1 => println!("Value was less than 2"), +LL | _ => println!("Value is {}", s.lock().deref()), + | ---------------- another value with significant `Drop` created here +LL | }; + | - temporary lives until here | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match and create a copy | LL ~ let value = *s.lock().deref().deref(); LL ~ match value { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:479:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:492:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | matcher => println!("Value is {}", s.lock().deref()), + | ---------------- another value with significant `Drop` created here +LL | _ => println!("Value was not a match"), +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:498:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:511:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | _ => { +LL | println!("{}", mutex.lock().unwrap().i); + | --------------------- another value with significant `Drop` created here +LL | }, +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ mutex.lock().unwrap().i = i; LL ~ match () { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:504:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:517:11 | LL | match i = mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | _ => { +LL | println!("{}", mutex.lock().unwrap().i); + | --------------------- another value with significant `Drop` created here +LL | }, +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ i = mutex.lock().unwrap().i; LL ~ match () { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:510:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:523:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | _ => { +LL | println!("{}", mutex.lock().unwrap().i); + | --------------------- another value with significant `Drop` created here +LL | }, +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ mutex.lock().unwrap().i += 1; LL ~ match () { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:516:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:529:11 | LL | match i += mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | +LL | _ => { +LL | println!("{}", mutex.lock().unwrap().i); + | --------------------- another value with significant `Drop` created here +LL | }, +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior help: try moving the temporary above the match | LL ~ i += mutex.lock().unwrap().i; LL ~ match () { | -error: temporary with significant drop in match scrutinee - --> $DIR/significant_drop_in_scrutinee.rs:579:11 +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:592:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior -error: temporary with significant drop in for loop - --> $DIR/significant_drop_in_scrutinee.rs:589:14 +error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression + --> $DIR/significant_drop_in_scrutinee.rs:602:14 | LL | for s in rwlock.read().unwrap().iter() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | println!("{}", s); +LL | } + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior + +error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression + --> $DIR/significant_drop_in_scrutinee.rs:617:11 + | +LL | match mutex.lock().unwrap().foo() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | }; + | - temporary lives until here + | + = note: this might lead to deadlocks or other unexpected behavior +help: try moving the temporary above the match + | +LL ~ let value = mutex.lock().unwrap().foo(); +LL ~ match value { + | -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr index 318faf2571758..4d2b9ec5f903a 100644 --- a/src/tools/clippy/tests/ui/single_match.stderr +++ b/src/tools/clippy/tests/ui/single_match.stderr @@ -38,6 +38,15 @@ LL | | _ => {}, LL | | }; | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }` +error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match.rs:54:5 + | +LL | / match x { +LL | | Some(y) => dummy(), +LL | | None => (), +LL | | }; + | |_____^ help: try this: `if let Some(y) = x { dummy() }` + error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:59:5 | @@ -146,5 +155,5 @@ LL | | (..) => {}, LL | | } | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` -error: aborting due to 15 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs index 82387f3d80b77..70d6febb71f9d 100644 --- a/src/tools/clippy/tests/ui/single_match_else.rs +++ b/src/tools/clippy/tests/ui/single_match_else.rs @@ -97,4 +97,23 @@ fn main() { return; }, } + + // lint here + use std::convert::Infallible; + match Result::<i32, Infallible>::Ok(1) { + Ok(a) => println!("${:?}", a), + Err(_) => { + println!("else block"); + return; + } + } + + use std::borrow::Cow; + match Cow::from("moo") { + Cow::Owned(a) => println!("${:?}", a), + Cow::Borrowed(_) => { + println!("else block"); + return; + } + } } diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr index 7756c6f204e67..38fd9c6a6782a 100644 --- a/src/tools/clippy/tests/ui/single_match_else.stderr +++ b/src/tools/clippy/tests/ui/single_match_else.stderr @@ -20,5 +20,85 @@ LL + None LL ~ }; | -error: aborting due to previous error +error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:84:5 + | +LL | / match Some(1) { +LL | | Some(a) => println!("${:?}", a), +LL | | None => { +LL | | println!("else block"); +LL | | return +LL | | }, +LL | | } + | |_____^ + | +help: try this + | +LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else { +LL + println!("else block"); +LL + return +LL + } + | + +error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:93:5 + | +LL | / match Some(1) { +LL | | Some(a) => println!("${:?}", a), +LL | | None => { +LL | | println!("else block"); +LL | | return; +LL | | }, +LL | | } + | |_____^ + | +help: try this + | +LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else { +LL + println!("else block"); +LL + return; +LL + } + | + +error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:103:5 + | +LL | / match Result::<i32, Infallible>::Ok(1) { +LL | | Ok(a) => println!("${:?}", a), +LL | | Err(_) => { +LL | | println!("else block"); +LL | | return; +LL | | } +LL | | } + | |_____^ + | +help: try this + | +LL ~ if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else { +LL + println!("else block"); +LL + return; +LL + } + | + +error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:112:5 + | +LL | / match Cow::from("moo") { +LL | | Cow::Owned(a) => println!("${:?}", a), +LL | | Cow::Borrowed(_) => { +LL | | println!("else block"); +LL | | return; +LL | | } +LL | | } + | |_____^ + | +help: try this + | +LL ~ if let Cow::Owned(a) = Cow::from("moo") { println!("${:?}", a) } else { +LL + println!("else block"); +LL + return; +LL + } + | + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs index 7e3d357ae50dc..16be9f6d203aa 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs @@ -19,6 +19,9 @@ fn extend_vector() { // Extend with mismatching expression should not be warned let mut vec3 = Vec::with_capacity(24322); vec3.extend(repeat(0).take(2)); + + let mut vec4 = Vec::with_capacity(len); + vec4.extend(repeat(0).take(vec4.capacity())); } fn mixed_extend_resize_vector() { @@ -48,6 +51,9 @@ fn resize_vector() { let mut vec3 = Vec::with_capacity(len - 10); vec3.resize(len - 10, 0); + let mut vec4 = Vec::with_capacity(len); + vec4.resize(vec4.capacity(), 0); + // Reinitialization should be warned vec1 = Vec::with_capacity(10); vec1.resize(10, 0); diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr index 5d2788ec26086..cb3ce3e95a7af 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr @@ -17,7 +17,15 @@ LL | vec2.extend(repeat(0).take(len - 10)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:31:5 + --> $DIR/slow_vector_initialization.rs:24:5 + | +LL | let mut vec4 = Vec::with_capacity(len); + | ----------------------- help: consider replace allocation with: `vec![0; len]` +LL | vec4.extend(repeat(0).take(vec4.capacity())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: slow zero-filling initialization + --> $DIR/slow_vector_initialization.rs:34:5 | LL | let mut resized_vec = Vec::with_capacity(30); | ---------------------- help: consider replace allocation with: `vec![0; 30]` @@ -25,7 +33,7 @@ LL | resized_vec.resize(30, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:34:5 + --> $DIR/slow_vector_initialization.rs:37:5 | LL | let mut extend_vec = Vec::with_capacity(30); | ---------------------- help: consider replace allocation with: `vec![0; 30]` @@ -33,7 +41,7 @@ LL | extend_vec.extend(repeat(0).take(30)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:41:5 + --> $DIR/slow_vector_initialization.rs:44:5 | LL | let mut vec1 = Vec::with_capacity(len); | ----------------------- help: consider replace allocation with: `vec![0; len]` @@ -41,7 +49,7 @@ LL | vec1.resize(len, 0); | ^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:49:5 + --> $DIR/slow_vector_initialization.rs:52:5 | LL | let mut vec3 = Vec::with_capacity(len - 10); | ---------------------------- help: consider replace allocation with: `vec![0; len - 10]` @@ -49,12 +57,20 @@ LL | vec3.resize(len - 10, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:53:5 + --> $DIR/slow_vector_initialization.rs:55:5 + | +LL | let mut vec4 = Vec::with_capacity(len); + | ----------------------- help: consider replace allocation with: `vec![0; len]` +LL | vec4.resize(vec4.capacity(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: slow zero-filling initialization + --> $DIR/slow_vector_initialization.rs:59:5 | LL | vec1 = Vec::with_capacity(10); | ---------------------- help: consider replace allocation with: `vec![0; 10]` LL | vec1.resize(10, 0); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed new file mode 100644 index 0000000000000..e5fe9133f975e --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed @@ -0,0 +1,78 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::transmute_ptr_to_ref)] +#![allow(clippy::match_single_binding)] + +unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) { + let _: &T = &*p; + let _: &T = &*p; + + let _: &mut T = &mut *m; + let _: &mut T = &mut *m; + + let _: &T = &*m; + let _: &T = &*m; + + let _: &mut T = &mut *(p as *mut T); + let _ = &mut *(p as *mut T); + + let _: &T = &*(o as *const T); + let _: &T = &*(o as *const T); + + let _: &mut T = &mut *(om as *mut T); + let _: &mut T = &mut *(om as *mut T); + + let _: &T = &*(om as *const T); + let _: &T = &*(om as *const T); +} + +fn _issue1231() { + struct Foo<'a, T> { + bar: &'a T, + } + + let raw = 42 as *const i32; + let _: &Foo<u8> = unsafe { &*raw.cast::<Foo<_>>() }; + + let _: &Foo<&u8> = unsafe { &*raw.cast::<Foo<&_>>() }; + + type Bar<'a> = &'a u8; + let raw = 42 as *const i32; + unsafe { &*(raw as *const u8) }; +} + +unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { + match 0 { + 0 => &*x.cast::<&u32>(), + 1 => &*y.cast::<&u32>(), + 2 => &*x.cast::<&'b u32>(), + _ => &*y.cast::<&'b u32>(), + } +} + +unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { + #![clippy::msrv = "1.38"] + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = &*a; + let _: &u32 = &*a.cast::<u32>(); + match 0 { + 0 => &*x.cast::<&u32>(), + _ => &*x.cast::<&'b u32>(), + } +} + +unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { + #![clippy::msrv = "1.37"] + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = &*a; + let _: &u32 = &*(a as *const u32); + match 0 { + 0 => &*(x as *const () as *const &u32), + _ => &*(x as *const () as *const &'b u32), + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs index ba35c6adc4dee..fe49cdc324fdd 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs @@ -1,4 +1,8 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] #![warn(clippy::transmute_ptr_to_ref)] +#![allow(clippy::match_single_binding)] unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = std::mem::transmute(p); @@ -23,7 +27,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = &*(om as *const T); } -fn issue1231() { +fn _issue1231() { struct Foo<'a, T> { bar: &'a T, } @@ -38,4 +42,37 @@ fn issue1231() { unsafe { std::mem::transmute::<_, Bar>(raw) }; } +unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { + match 0 { + 0 => std::mem::transmute(x), + 1 => std::mem::transmute(y), + 2 => std::mem::transmute::<_, &&'b u32>(x), + _ => std::mem::transmute::<_, &&'b u32>(y), + } +} + +unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { + #![clippy::msrv = "1.38"] + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = std::mem::transmute(a); + let _: &u32 = std::mem::transmute::<_, &u32>(a); + match 0 { + 0 => std::mem::transmute(x), + _ => std::mem::transmute::<_, &&'b u32>(x), + } +} + +unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { + #![clippy::msrv = "1.37"] + let a = 0u32; + let a = &a as *const u32; + let _: &u32 = std::mem::transmute(a); + let _: &u32 = std::mem::transmute::<_, &u32>(a); + match 0 { + 0 => std::mem::transmute(x), + _ => std::mem::transmute::<_, &&'b u32>(x), + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr index df0598a58cd36..2993e5e7b0c91 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr @@ -1,5 +1,5 @@ error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:4:17 + --> $DIR/transmute_ptr_to_ref.rs:8:17 | LL | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` @@ -7,58 +7,130 @@ LL | let _: &T = std::mem::transmute(p); = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:7:21 + --> $DIR/transmute_ptr_to_ref.rs:11:21 | LL | let _: &mut T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:10:17 + --> $DIR/transmute_ptr_to_ref.rs:14:17 | LL | let _: &T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:13:21 + --> $DIR/transmute_ptr_to_ref.rs:17:21 | LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:16:17 + --> $DIR/transmute_ptr_to_ref.rs:20:17 | LL | let _: &T = std::mem::transmute(o); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:19:21 + --> $DIR/transmute_ptr_to_ref.rs:23:21 | LL | let _: &mut T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:22:17 + --> $DIR/transmute_ptr_to_ref.rs:26:17 | LL | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` -error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<u8>`) - --> $DIR/transmute_ptr_to_ref.rs:32:32 +error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<u8>`) + --> $DIR/transmute_ptr_to_ref.rs:36:32 | LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<_>)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()` -error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<&u8>`) - --> $DIR/transmute_ptr_to_ref.rs:34:33 +error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<&u8>`) + --> $DIR/transmute_ptr_to_ref.rs:38:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<&_>)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> $DIR/transmute_ptr_to_ref.rs:38:14 + --> $DIR/transmute_ptr_to_ref.rs:42:14 | LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` -error: aborting due to 10 previous errors +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:47:14 + | +LL | 0 => std::mem::transmute(x), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:48:14 + | +LL | 1 => std::mem::transmute(y), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:49:14 + | +LL | 2 => std::mem::transmute::<_, &&'b u32>(x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:50:14 + | +LL | _ => std::mem::transmute::<_, &&'b u32>(y), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> $DIR/transmute_ptr_to_ref.rs:58:19 + | +LL | let _: &u32 = std::mem::transmute(a); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> $DIR/transmute_ptr_to_ref.rs:59:19 + | +LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:61:14 + | +LL | 0 => std::mem::transmute(x), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:62:14 + | +LL | _ => std::mem::transmute::<_, &&'b u32>(x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> $DIR/transmute_ptr_to_ref.rs:70:19 + | +LL | let _: &u32 = std::mem::transmute(a); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` + +error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) + --> $DIR/transmute_ptr_to_ref.rs:71:19 + | +LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:73:14 + | +LL | 0 => std::mem::transmute(x), + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` + +error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) + --> $DIR/transmute_ptr_to_ref.rs:74:14 + | +LL | _ => std::mem::transmute::<_, &&'b u32>(x), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` + +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs index ea3dce17081b1..8f78f16a0a1a6 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs @@ -113,6 +113,44 @@ mod issue5876 { } } +fn _ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> { + Some(x) +} + +#[allow(clippy::needless_lifetimes)] +fn _ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> { + Some(x) +} + +fn _with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 { + if true { x } else { y } +} + +async fn _async_implicit(x: &u32) -> &u32 { + x +} + +#[allow(clippy::needless_lifetimes)] +async fn _async_explicit<'a>(x: &'a u32) -> &'a u32 { + x +} + +fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { + y +} + +fn _return_ptr(x: &u32) -> *const u32 { + x +} + +fn _return_field_ptr(x: &(u32, u32)) -> *const u32 { + &x.0 +} + +fn _return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 { + core::ptr::addr_of!(x.0) +} + fn main() { let (mut foo, bar) = (Foo(0), Bar([0; 24])); let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0); diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr index a88d35f3ea5a9..66ecb3d8e77ac 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr @@ -106,5 +106,11 @@ error: this argument (N byte) is passed by reference, but would be more efficien LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` -error: aborting due to 17 previous errors +error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) + --> $DIR/trivially_copy_pass_by_ref.rs:138:37 + | +LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { + | ^^^^^^^ help: consider passing by value instead: `u32` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs index 2a3a506a57b14..4ca7f29b34cd0 100644 --- a/src/tools/clippy/tests/ui/unused_async.rs +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -1,5 +1,8 @@ #![warn(clippy::unused_async)] +use std::future::Future; +use std::pin::Pin; + async fn foo() -> i32 { 4 } @@ -8,6 +11,37 @@ async fn bar() -> i32 { foo().await } +struct S; + +impl S { + async fn unused(&self) -> i32 { + 1 + } + + async fn used(&self) -> i32 { + self.unused().await + } +} + +trait AsyncTrait { + fn trait_method() -> Pin<Box<dyn Future<Output = i32>>>; +} + +macro_rules! async_trait_impl { + () => { + impl AsyncTrait for S { + fn trait_method() -> Pin<Box<dyn Future<Output = i32>>> { + async fn unused() -> i32 { + 5 + } + + Box::pin(unused()) + } + } + }; +} +async_trait_impl!(); + fn main() { foo(); bar(); diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr index cc6096d65d9f3..8b8ad065a4caa 100644 --- a/src/tools/clippy/tests/ui/unused_async.stderr +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:3:1 + --> $DIR/unused_async.rs:6:1 | LL | / async fn foo() -> i32 { LL | | 4 @@ -9,5 +9,15 @@ LL | | } = note: `-D clippy::unused-async` implied by `-D warnings` = help: consider removing the `async` from this function -error: aborting due to previous error +error: unused `async` for function with no await statements + --> $DIR/unused_async.rs:17:5 + | +LL | / async fn unused(&self) -> i32 { +LL | | 1 +LL | | } + | |_____^ + | + = help: consider removing the `async` from this function + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs index 21d66d5df79ec..d20977d55d29d 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.rs +++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs @@ -44,6 +44,12 @@ fn in_struct_field() { s._underscore_field += 1; } +/// Tests that we do not lint if the struct field is used in code created with derive. +#[derive(Clone, Debug)] +pub struct UnderscoreInStruct { + _foo: u32, +} + /// Tests that we do not lint if the underscore is not a prefix fn non_prefix_underscore(some_foo: u32) -> u32 { some_foo + 1 diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr index 790b849210c9b..61a9161d212da 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr +++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr @@ -31,7 +31,7 @@ LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:99:16 + --> $DIR/used_underscore_binding.rs:105:16 | LL | uses_i(_i); | ^^ diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index e431661d180de..90cb8945e77ff 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_asref)] +#![allow(clippy::explicit_auto_deref)] use std::fmt::Debug; diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index 6ae931d7aa481..cb9f8ae5909a5 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_asref)] +#![allow(clippy::explicit_auto_deref)] use std::fmt::Debug; diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr index 5876b54aca8f0..b21c67bb3645f 100644 --- a/src/tools/clippy/tests/ui/useless_asref.stderr +++ b/src/tools/clippy/tests/ui/useless_asref.stderr @@ -1,5 +1,5 @@ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:43:18 + --> $DIR/useless_asref.rs:44:18 | LL | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try this: `rstr` @@ -11,61 +11,61 @@ LL | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:45:20 + --> $DIR/useless_asref.rs:46:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try this: `rslice` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:49:21 + --> $DIR/useless_asref.rs:50:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:51:20 + --> $DIR/useless_asref.rs:52:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:58:20 + --> $DIR/useless_asref.rs:59:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:60:18 + --> $DIR/useless_asref.rs:61:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:65:21 + --> $DIR/useless_asref.rs:66:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:67:20 + --> $DIR/useless_asref.rs:68:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:71:16 + --> $DIR/useless_asref.rs:72:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:121:13 + --> $DIR/useless_asref.rs:122:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try this: `mrt` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:123:12 + --> $DIR/useless_asref.rs:124:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try this: `mrt` diff --git a/src/tools/clippy/tests/ui/while_let_loop.rs b/src/tools/clippy/tests/ui/while_let_loop.rs index 3ce699f551b20..c42e2a79a9bf9 100644 --- a/src/tools/clippy/tests/ui/while_let_loop.rs +++ b/src/tools/clippy/tests/ui/while_let_loop.rs @@ -117,3 +117,29 @@ fn issue1948() { } }; } + +fn issue_7913(m: &std::sync::Mutex<Vec<u32>>) { + // Don't lint. The lock shouldn't be held while printing. + loop { + let x = if let Some(x) = m.lock().unwrap().pop() { + x + } else { + break; + }; + + println!("{}", x); + } +} + +fn issue_5715(mut m: core::cell::RefCell<Option<u32>>) { + // Don't lint. The temporary from `borrow_mut` must be dropped before overwriting the `RefCell`. + loop { + let x = if let &mut Some(x) = &mut *m.borrow_mut() { + x + } else { + break; + }; + + m = core::cell::RefCell::new(Some(x + 1)); + } +} diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed index cb8892a3f009b..e9ff64431e19d 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed @@ -6,7 +6,8 @@ unreachable_code, unused_mut, dead_code, - clippy::equatable_if_let + clippy::equatable_if_let, + clippy::manual_find )] fn base() { diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs index d91571844959e..03da39526b2fd 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs @@ -6,7 +6,8 @@ unreachable_code, unused_mut, dead_code, - clippy::equatable_if_let + clippy::equatable_if_let, + clippy::manual_find )] fn base() { diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr index fb2b0f2467c0d..42859243855a6 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:14:5 + --> $DIR/while_let_on_iterator.rs:15:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -7,85 +7,85 @@ LL | while let Option::Some(x) = iter.next() { = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:19:5 + --> $DIR/while_let_on_iterator.rs:20:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:24:5 + --> $DIR/while_let_on_iterator.rs:25:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:100:9 + --> $DIR/while_let_on_iterator.rs:101:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:107:9 + --> $DIR/while_let_on_iterator.rs:108:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:120:9 + --> $DIR/while_let_on_iterator.rs:121:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:140:9 + --> $DIR/while_let_on_iterator.rs:141:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:197:9 + --> $DIR/while_let_on_iterator.rs:198:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:208:5 + --> $DIR/while_let_on_iterator.rs:209:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:210:9 + --> $DIR/while_let_on_iterator.rs:211:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:219:9 + --> $DIR/while_let_on_iterator.rs:220:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:228:9 + --> $DIR/while_let_on_iterator.rs:229:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:245:9 + --> $DIR/while_let_on_iterator.rs:246:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:260:13 + --> $DIR/while_let_on_iterator.rs:261:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: manual `!RangeInclusive::contains` implementation - --> $DIR/while_let_on_iterator.rs:261:20 + --> $DIR/while_let_on_iterator.rs:262:20 | LL | if i < 3 || i > 7 { | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` @@ -93,49 +93,49 @@ LL | if i < 3 || i > 7 { = note: `-D clippy::manual-range-contains` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:292:13 + --> $DIR/while_let_on_iterator.rs:293:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:321:5 + --> $DIR/while_let_on_iterator.rs:322:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:333:9 + --> $DIR/while_let_on_iterator.rs:334:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:347:5 + --> $DIR/while_let_on_iterator.rs:348:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:358:5 + --> $DIR/while_let_on_iterator.rs:359:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:393:5 + --> $DIR/while_let_on_iterator.rs:394:5 | LL | while let Some(x) = s.x.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:400:5 + --> $DIR/while_let_on_iterator.rs:401:5 | LL | while let Some(x) = x[0].next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:407:5 + --> $DIR/while_let_on_iterator.rs:408:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` diff --git a/src/tools/clippy/tests/ui/zero_div_zero.rs b/src/tools/clippy/tests/ui/zero_div_zero.rs index ed3a9208fc3f0..968c58f40aefa 100644 --- a/src/tools/clippy/tests/ui/zero_div_zero.rs +++ b/src/tools/clippy/tests/ui/zero_div_zero.rs @@ -1,4 +1,4 @@ -#[allow(unused_variables)] +#[allow(unused_variables, clippy::eq_op)] #[warn(clippy::zero_divided_by_zero)] fn main() { let nan = 0.0 / 0.0; diff --git a/src/tools/clippy/tests/ui/zero_div_zero.stderr b/src/tools/clippy/tests/ui/zero_div_zero.stderr index 0931dd32e7af2..86563542e0602 100644 --- a/src/tools/clippy/tests/ui/zero_div_zero.stderr +++ b/src/tools/clippy/tests/ui/zero_div_zero.stderr @@ -1,11 +1,3 @@ -error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:4:15 - | -LL | let nan = 0.0 / 0.0; - | ^^^^^^^^^ - | - = note: `#[deny(clippy::eq_op)]` on by default - error: constant division of `0.0` with `0.0` will always result in NaN --> $DIR/zero_div_zero.rs:4:15 | @@ -15,12 +7,6 @@ LL | let nan = 0.0 / 0.0; = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` = help: consider using `f64::NAN` if you would like a constant representing NaN -error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:5:19 - | -LL | let f64_nan = 0.0 / 0.0f64; - | ^^^^^^^^^^^^ - error: constant division of `0.0` with `0.0` will always result in NaN --> $DIR/zero_div_zero.rs:5:19 | @@ -29,12 +15,6 @@ LL | let f64_nan = 0.0 / 0.0f64; | = help: consider using `f64::NAN` if you would like a constant representing NaN -error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:6:25 - | -LL | let other_f64_nan = 0.0f64 / 0.0; - | ^^^^^^^^^^^^ - error: constant division of `0.0` with `0.0` will always result in NaN --> $DIR/zero_div_zero.rs:6:25 | @@ -43,12 +23,6 @@ LL | let other_f64_nan = 0.0f64 / 0.0; | = help: consider using `f64::NAN` if you would like a constant representing NaN -error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:7:28 - | -LL | let one_more_f64_nan = 0.0f64 / 0.0f64; - | ^^^^^^^^^^^^^^^ - error: constant division of `0.0` with `0.0` will always result in NaN --> $DIR/zero_div_zero.rs:7:28 | @@ -57,5 +31,5 @@ LL | let one_more_f64_nan = 0.0f64 / 0.0f64; | = help: consider using `f64::NAN` if you would like a constant representing NaN -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html index 4999cce75114b..6183089911bdc 100644 --- a/src/tools/clippy/util/gh-pages/index.html +++ b/src/tools/clippy/util/gh-pages/index.html @@ -10,6 +10,7 @@ <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> + <meta name="description" content="A collection of lints to catch common mistakes and improve your Rust code."> <title>Clippy Lints</title> diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index bdf26d040ad14..be81ff881f3a8 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -269,6 +269,10 @@ pub struct Config { /// Flags to pass to the compiler when building for the target pub target_rustcflags: Option<String>, + /// Whether tests should be optimized by default. Individual test-suites and test files may + /// override this setting. + pub optimize_tests: bool, + /// What panic strategy the target is built with. Unwind supports Abort, but /// not vice versa. pub target_panic: PanicStrategy, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 5352f7c6fe0fa..17f2b77dab052 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -60,6 +60,8 @@ impl EarlyProps { pub struct TestProps { // Lines that should be expected, in order, on standard out pub error_patterns: Vec<String>, + // Regexes that should be expected, in order, on standard out + pub regex_error_patterns: Vec<String>, // Extra flags to pass to the compiler pub compile_flags: Vec<String>, // Extra flags to pass when the compiled code is run (such as --bench) @@ -163,6 +165,7 @@ pub struct TestProps { mod directives { pub const ERROR_PATTERN: &'static str = "error-pattern"; + pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern"; pub const COMPILE_FLAGS: &'static str = "compile-flags"; pub const RUN_FLAGS: &'static str = "run-flags"; pub const SHOULD_ICE: &'static str = "should-ice"; @@ -200,6 +203,7 @@ impl TestProps { pub fn new() -> Self { TestProps { error_patterns: vec![], + regex_error_patterns: vec![], compile_flags: vec![], run_flags: None, pp_exact: None, @@ -244,6 +248,7 @@ impl TestProps { // copy over select properties to the aux build: props.incremental_dir = self.incremental_dir.clone(); + props.ignore_pass = true; props.load_from(testfile, cfg, config); props @@ -284,6 +289,12 @@ impl TestProps { &mut self.error_patterns, |r| r, ); + config.push_name_value_directive( + ln, + REGEX_ERROR_PATTERN, + &mut self.regex_error_patterns, + |r| r, + ); if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned())); @@ -293,7 +304,7 @@ impl TestProps { } if let Some(edition) = config.parse_edition(ln) { - self.compile_flags.push(format!("--edition={}", edition)); + self.compile_flags.push(format!("--edition={}", edition.trim())); has_edition = true; } @@ -395,7 +406,29 @@ impl TestProps { ); config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut self.stderr_per_bitwidth); config.set_name_directive(ln, INCREMENTAL, &mut self.incremental); - config.set_name_directive(ln, KNOWN_BUG, &mut self.known_bug); + + // Unlike the other `name_value_directive`s this needs to be handled manually, + // because it sets a `bool` flag. + if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) { + let known_bug = known_bug.trim(); + if known_bug == "unknown" + || known_bug.split(',').all(|issue_ref| { + issue_ref + .trim() + .split_once('#') + .filter(|(_, number)| { + number.chars().all(|digit| digit.is_numeric()) + }) + .is_some() + }) + { + self.known_bug = true; + } else { + panic!( + "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `unknown`." + ); + } + } config.set_name_value_directive(ln, MIR_UNIT_TEST, &mut self.mir_unit_test, |s| { s.trim().to_string() }); diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index e23cccf6cd129..a8a151ca114d2 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -102,6 +102,7 @@ pub fn parse_config(args: Vec<String>) -> Config { ) .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optflag("", "optimize-tests", "run tests with optimizations enabled") .optopt("", "target-panic", "what panic strategy the target supports", "unwind | abort") .optflag("", "verbose", "run tests verbosely, showing all output") .optflag( @@ -253,6 +254,7 @@ pub fn parse_config(args: Vec<String>) -> Config { runtool: matches.opt_str("runtool"), host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")), target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")), + optimize_tests: matches.opt_present("optimize-tests"), target_panic: match matches.opt_str("target-panic").as_deref() { Some("unwind") | None => PanicStrategy::Unwind, Some("abort") => PanicStrategy::Abort, @@ -351,11 +353,6 @@ pub fn opt_str2(maybestr: Option<String>) -> String { } pub fn run_tests(config: Config) { - // FIXME(#33435) Avoid spurious failures in codegen-units/partitioning tests. - if let Mode::CodegenUnits = config.mode { - let _ = fs::remove_dir_all("tmp/partitioning-tests"); - } - // If we want to collect rustfix coverage information, // we first make sure that the coverage file does not exist. // It will be created later on. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index b758bb9cf6790..5517b5a12c393 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -323,12 +323,13 @@ impl<'test> TestCx<'test> { let output_to_check = self.get_output(&proc_res); let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); if !expected_errors.is_empty() { - if !self.props.error_patterns.is_empty() { + if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() + { self.fatal("both error pattern and expected errors specified"); } self.check_expected_errors(expected_errors, &proc_res); } else { - self.check_error_patterns(&output_to_check, &proc_res, pm); + self.check_all_error_patterns(&output_to_check, &proc_res, pm); } if self.props.should_ice { match proc_res.status.code() { @@ -363,7 +364,7 @@ impl<'test> TestCx<'test> { let output_to_check = self.get_output(&proc_res); self.check_correct_failure_status(&proc_res); - self.check_error_patterns(&output_to_check, &proc_res, pm); + self.check_all_error_patterns(&output_to_check, &proc_res, pm); } fn get_output(&self, proc_res: &ProcRes) -> String { @@ -1222,14 +1223,13 @@ impl<'test> TestCx<'test> { } } - fn check_error_patterns( + fn check_all_error_patterns( &self, output_to_check: &str, proc_res: &ProcRes, pm: Option<PassMode>, ) { - debug!("check_error_patterns"); - if self.props.error_patterns.is_empty() { + if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() { if pm.is_some() { // FIXME(#65865) return; @@ -1243,13 +1243,8 @@ impl<'test> TestCx<'test> { let mut missing_patterns: Vec<String> = Vec::new(); - for pattern in &self.props.error_patterns { - if output_to_check.contains(pattern.trim()) { - debug!("found error pattern {}", pattern); - } else { - missing_patterns.push(pattern.to_string()); - } - } + self.check_error_patterns(output_to_check, &mut missing_patterns); + self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns); if missing_patterns.is_empty() { return; @@ -1268,6 +1263,44 @@ impl<'test> TestCx<'test> { } } + fn check_error_patterns(&self, output_to_check: &str, missing_patterns: &mut Vec<String>) { + debug!("check_error_patterns"); + for pattern in &self.props.error_patterns { + if output_to_check.contains(pattern.trim()) { + debug!("found error pattern {}", pattern); + } else { + missing_patterns.push(pattern.to_string()); + } + } + } + + fn check_regex_error_patterns( + &self, + output_to_check: &str, + proc_res: &ProcRes, + missing_patterns: &mut Vec<String>, + ) { + debug!("check_regex_error_patterns"); + + for pattern in &self.props.regex_error_patterns { + let pattern = pattern.trim(); + let re = match Regex::new(pattern) { + Ok(re) => re, + Err(err) => { + self.fatal_proc_rec( + &format!("invalid regex error pattern '{}': {:?}", pattern, err), + proc_res, + ); + } + }; + if re.is_match(output_to_check) { + debug!("found regex error pattern {}", pattern); + } else { + missing_patterns.push(pattern.to_string()); + } + } + } + fn check_no_compiler_crash(&self, proc_res: &ProcRes, should_ice: bool) { match proc_res.status.code() { Some(101) if !should_ice => { @@ -1862,12 +1895,39 @@ impl<'test> TestCx<'test> { } } + if self.config.optimize_tests && !is_rustdoc { + match self.config.mode { + Ui => { + // If optimize-tests is true we still only want to optimize tests that actually get + // executed and that don't specify their own optimization levels. + // Note: aux libs don't have a pass-mode, so they won't get optimized + // unless compile-flags are set in the aux file. + if self.config.optimize_tests + && self.props.pass_mode(&self.config) == Some(PassMode::Run) + && !self + .props + .compile_flags + .iter() + .any(|arg| arg == "-O" || arg.contains("opt-level")) + { + rustc.arg("-O"); + } + } + DebugInfo => { /* debuginfo tests must be unoptimized */ } + _ => { + rustc.arg("-O"); + } + } + } + match self.config.mode { Incremental => { // If we are extracting and matching errors in the new // fashion, then you want JSON mode. Old-skool error // patterns still match the raw compiler output. - if self.props.error_patterns.is_empty() { + if self.props.error_patterns.is_empty() + && self.props.regex_error_patterns.is_empty() + { rustc.args(&["--error-format", "json"]); rustc.args(&["--json", "future-incompat"]); } @@ -1882,6 +1942,8 @@ impl<'test> TestCx<'test> { rustc.arg("-Ccodegen-units=1"); rustc.arg("-Zui-testing"); rustc.arg("-Zdeduplicate-diagnostics=no"); + // FIXME: use this for other modes too, for perf? + rustc.arg("-Cstrip=debuginfo"); } MirOpt => { rustc.args(&[ @@ -3241,9 +3303,11 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("test run succeeded!", &proc_res); } - if !self.props.error_patterns.is_empty() { + if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() + { // "// error-pattern" comments - self.check_error_patterns(&proc_res.stderr, &proc_res, pm); + let output_to_check = self.get_output(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res, pm); } } @@ -3257,14 +3321,16 @@ impl<'test> TestCx<'test> { self.props.error_patterns ); if !explicit && self.config.compare_mode.is_none() { - let check_patterns = - should_run == WillExecute::No && !self.props.error_patterns.is_empty(); + let check_patterns = should_run == WillExecute::No + && (!self.props.error_patterns.is_empty() + || !self.props.regex_error_patterns.is_empty()); let check_annotations = !check_patterns || !expected_errors.is_empty(); if check_patterns { // "// error-pattern" comments - self.check_error_patterns(&proc_res.stderr, &proc_res, pm); + let output_to_check = self.get_output(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res, pm); } if check_annotations { diff --git a/src/tools/miri b/src/tools/miri index 655eed35b7ca7..cde87d18239b8 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 655eed35b7ca7cae08f21ead6151b9dfb69794ff +Subproject commit cde87d18239b8d9afa9c6bf1051bf5573dbf326e diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 04a1d257bc094..fe5195738c10a 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -30,7 +30,7 @@ # These should be collaborators of the rust-lang/rust repository (with at least # read privileges on it). CI will fail otherwise. MAINTAINERS = { - 'miri': {'oli-obk', 'RalfJung', 'eddyb'}, + 'miri': {'oli-obk', 'RalfJung'}, 'rls': {'Xanewok'}, 'rustfmt': {'topecongiro', 'calebcartwright'}, 'book': {'carols10cents', 'steveklabnik'}, diff --git a/src/tools/rls b/src/tools/rls index 27f4044df03d1..fcf1f94c9ab2a 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 27f4044df03d15c7c38a483c3e4635cf4f51807d +Subproject commit fcf1f94c9ab2acc18cfd4368a4aeb38e77da9649 diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 427061da19723..5342f47f42766 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 427061da19723f2206fe4dcb175c9c43b9a6193d +Subproject commit 5342f47f4276641ddb5f0a5e08fb307742d6cdc4 diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 5254dbfd25d52..300b5ec61ef38 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 5254dbfd25d5284728ab624dca1969d61427a0db +Subproject commit 300b5ec61ef38855a07e6bb4955a37aa1c414c00 diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index f074eb941dca2..bd08e0ede0bfa 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -clap = "2.25.0" +clap = "3.1.1" env_logger = "0.7.1" [dependencies.mdbook] diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 63d84ae9732f7..3c7dc0183d776 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -3,54 +3,57 @@ use clap::crate_version; use std::env; use std::path::{Path, PathBuf}; -use clap::{App, AppSettings, ArgMatches, SubCommand}; +use clap::{arg, ArgMatches, Command}; use mdbook::errors::Result as Result3; use mdbook::MDBook; fn main() { + let crate_version = format!("v{}", crate_version!()); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); - let d_message = "-d, --dest-dir=[dest-dir] -'The output directory for your book{n}(Defaults to ./book when omitted)'"; - let dir_message = "[dir] -'A directory for your book{n}(Defaults to Current Directory when omitted)'"; + let d_arg = arg!(-d --"dest-dir" <DEST_DIR> +"The output directory for your book\n(Defaults to ./book when omitted)") + .required(false); + let dir_arg = arg!([dir] +"A directory for your book\n(Defaults to Current Directory when omitted)"); - let matches = App::new("rustbook") + let matches = Command::new("rustbook") .about("Build a book with mdBook") .author("Steve Klabnik <steve@steveklabnik.com>") - .version(&*format!("v{}", crate_version!())) - .setting(AppSettings::SubcommandRequired) + .version(&*crate_version) + .subcommand_required(true) + .arg_required_else_help(true) .subcommand( - SubCommand::with_name("build") + Command::new("build") .about("Build the book from the markdown files") - .arg_from_usage(d_message) - .arg_from_usage(dir_message), + .arg(d_arg) + .arg(&dir_arg), ) .subcommand( - SubCommand::with_name("test") + Command::new("test") .about("Tests that a book's Rust code samples compile") - .arg_from_usage(dir_message), + .arg(dir_arg), ) .get_matches(); // Check which subcomamnd the user ran... match matches.subcommand() { - ("build", Some(sub_matches)) => { + Some(("build", sub_matches)) => { if let Err(e) = build(sub_matches) { handle_error(e); } } - ("test", Some(sub_matches)) => { + Some(("test", sub_matches)) => { if let Err(e) = test(sub_matches) { handle_error(e); } } - (_, _) => unreachable!(), + _ => unreachable!(), }; } // Build command implementation -pub fn build(args: &ArgMatches<'_>) -> Result3<()> { +pub fn build(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); let mut book = load_book(&book_dir)?; @@ -66,13 +69,13 @@ pub fn build(args: &ArgMatches<'_>) -> Result3<()> { Ok(()) } -fn test(args: &ArgMatches<'_>) -> Result3<()> { +fn test(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); let mut book = load_book(&book_dir)?; book.test(vec![]) } -fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf { +fn get_book_dir(args: &ArgMatches) -> PathBuf { if let Some(dir) = args.value_of("dir") { // Check if path is relative from current dir, or absolute... let p = Path::new(dir); diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 40aa0e8f715af..22c2d28d9f693 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -79,12 +79,14 @@ crossbeam-utils = { version = "0.8.0", features = ["nightly"] } libc = { version = "0.2.79", features = ["align"] } # Ensure default features of libz-sys, which are disabled in some scenarios. libz-sys = { version = "1.1.2" } +# same for regex +regex = { version = "1.5.5" } proc-macro2 = { version = "1", features = ["default"] } quote = { version = "1", features = ["default"] } rand_core_0_5 = { package = "rand_core", version = "0.5.1", features = ["getrandom", "alloc", "std"] } serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value", "unbounded_depth"] } -smallvec = { version = "1.6.1", features = ['union', 'may_dangle'] } +smallvec = { version = "1.8.1", features = ['union', 'may_dangle'] } syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit', 'visit-mut'] } url = { version = "2.0", features = ['serde'] } diff --git a/src/tools/rustfmt/.github/workflows/linux.yml b/src/tools/rustfmt/.github/workflows/linux.yml index 6a3f9d89d98fc..bce9b0c8d5a95 100644 --- a/src/tools/rustfmt/.github/workflows/linux.yml +++ b/src/tools/rustfmt/.github/workflows/linux.yml @@ -35,15 +35,5 @@ jobs: sh rustup-init.sh -y --default-toolchain none rustup target add ${{ matrix.target }} - - name: build - run: | - rustc -Vv - cargo -V - cargo build - env: - RUSTFLAGS: '-D warnings' - - - name: test - run: cargo test - env: - RUSTFLAGS: '-D warnings' + - name: Build and Test + run: ./ci/build_and_test.sh diff --git a/src/tools/rustfmt/.github/workflows/mac.yml b/src/tools/rustfmt/.github/workflows/mac.yml index 7dfda3142ca9d..89a980c42c5a0 100644 --- a/src/tools/rustfmt/.github/workflows/mac.yml +++ b/src/tools/rustfmt/.github/workflows/mac.yml @@ -32,11 +32,5 @@ jobs: sh rustup-init.sh -y --default-toolchain none rustup target add ${{ matrix.target }} - - name: build - run: | - rustc -Vv - cargo -V - cargo build - - - name: test - run: cargo test + - name: Build and Test + run: ./ci/build_and_test.sh diff --git a/src/tools/rustfmt/.github/workflows/windows.yml b/src/tools/rustfmt/.github/workflows/windows.yml index 4ebc296384905..ec37c714b0851 100644 --- a/src/tools/rustfmt/.github/workflows/windows.yml +++ b/src/tools/rustfmt/.github/workflows/windows.yml @@ -57,13 +57,6 @@ jobs: if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly' shell: bash - - name: build - run: | - rustc -Vv - cargo -V - cargo build - shell: cmd - - - name: test - run: cargo test + - name: Build and Test shell: cmd + run: ci\build_and_test.bat diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md index bfc155cd656a6..0c1893bf8c387 100644 --- a/src/tools/rustfmt/CHANGELOG.md +++ b/src/tools/rustfmt/CHANGELOG.md @@ -2,7 +2,29 @@ ## [Unreleased] -## [1.5.0] 2022-06-13 +## [1.5.1] 2022-06-24 + +**N.B** A bug was introduced in v1.5.0/nightly-2022-06-15 which modified formatting. If you happened to run rustfmt over your code with one of those ~10 nightlies it's possible you may have seen formatting changes, and you may see additional changes after this fix since that bug has now been reverted. + +### Fixed + +- Correct an issue introduced in v1.5.0 where formatting changes were unintentionally introduced in a few cases with a large/long construct in a right hand side position (e.g. a large chain on the RHS of a local/assignment statement) +- `cargo fmt --version` properly displays the version value again [#5395](https://github.com/rust-lang/rustfmt/issues/5395) + +### Changed + +- Properly sort imports containing raw identifiers [#3791](https://github.com/rust-lang/rustfmt/issues/3791) (note this is change version gated, and not applied by default) + +### Added + +- Add new configuration option, `doc_comment_code_block_width`, which allows for setting a shorter width limit to use for formatting code snippets in doc comments [#5384](https://github.com/rust-lang/rustfmt/issues/5384) + +### Install/Download Options +- **rustup (nightly)** - nightly-2022-06-24 +- **GitHub Release Binaries** - [Release v1.5.1](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.0) +- **Build from source** - [Tag v1.5.1](https://github.com/rust-lang/rustfmt/tree/v1.5.1), see instructions for how to [install rustfmt from source][install-from-source] + +## [1.5.0] 2022-06-14 ### Changed @@ -75,7 +97,7 @@ - Improved performance when formatting large and deeply nested expression trees, often found in generated code, which have many expressions that exceed `max_width` [#5128](https://github.com/rust-lang/rustfmt/issues/5128), [#4867](https://github.com/rust-lang/rustfmt/issues/4867), [#4476](https://github.com/rust-lang/rustfmt/issues/4476), [#5139](https://github.com/rust-lang/rustfmt/pull/5139) ### Install/Download Options -- **rustup (nightly)** - *pending* +- **rustup (nightly)** - nightly-2022-06-15 - **GitHub Release Binaries** - [Release v1.5.0](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.0) - **Build from source** - [Tag v1.5.0](https://github.com/rust-lang/rustfmt/tree/v1.5.0), see instructions for how to [install rustfmt from source][install-from-source] diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index 639d35886dcda..311df226da19d 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -485,7 +485,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.5.0" +version = "1.5.1" dependencies = [ "annotate-snippets", "anyhow", diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index f26e982406234..7a4e02d69eddc 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.5.0" +version = "1.5.1" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -65,3 +65,7 @@ rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" } rustc-workspace-hack = "1.0.0" # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. + +[package.metadata.rust-analyzer] +# This package uses #[feature(rustc_private)] +rustc_private = true diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md index 8c84614352ca2..8b96b9d36892a 100644 --- a/src/tools/rustfmt/Configurations.md +++ b/src/tools/rustfmt/Configurations.md @@ -926,6 +926,14 @@ fn add_one(x: i32) -> i32 { } ``` +## `doc_comment_code_block_width` + +Max width for code snippets included in doc comments. Only used if [`format_code_in_doc_comments`](#format_code_in_doc_comments) is true. + +- **Default value**: `100` +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Stable**: No (tracking issue: [#5359](https://github.com/rust-lang/rustfmt/issues/5359)) + ## `format_generated_files` Format generated files. A file is considered generated diff --git a/src/tools/rustfmt/ci/build_and_test.bat b/src/tools/rustfmt/ci/build_and_test.bat new file mode 100755 index 0000000000000..ef41017783feb --- /dev/null +++ b/src/tools/rustfmt/ci/build_and_test.bat @@ -0,0 +1,14 @@ +set "RUSTFLAGS=-D warnings" + +:: Print version information +rustc -Vv || exit /b 1 +cargo -V || exit /b 1 + +:: Build and test main crate +cargo build --locked || exit /b 1 +cargo test || exit /b 1 + +:: Build and test other crates +cd config_proc_macro || exit /b 1 +cargo build --locked || exit /b 1 +cargo test || exit /b 1 diff --git a/src/tools/rustfmt/ci/build_and_test.sh b/src/tools/rustfmt/ci/build_and_test.sh new file mode 100755 index 0000000000000..8fa0f67b0d021 --- /dev/null +++ b/src/tools/rustfmt/ci/build_and_test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -euo pipefail + +export RUSTFLAGS="-D warnings" + +# Print version information +rustc -Vv +cargo -V + +# Build and test main crate +cargo build --locked +cargo test + +# Build and test other crates +cd config_proc_macro +cargo build --locked +cargo test diff --git a/src/tools/rustfmt/ci/integration.sh b/src/tools/rustfmt/ci/integration.sh index 0269e3ee4af93..562d5d70c70ba 100755 --- a/src/tools/rustfmt/ci/integration.sh +++ b/src/tools/rustfmt/ci/integration.sh @@ -15,7 +15,7 @@ set -ex # it again. # #which cargo-fmt || cargo install --force -CFG_RELEASE=nightly CFG_RELEASE_CHANNEL=nightly cargo install --path . --force +CFG_RELEASE=nightly CFG_RELEASE_CHANNEL=nightly cargo install --path . --force --locked echo "Integration tests for: ${INTEGRATION}" cargo fmt -- --version diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.lock b/src/tools/rustfmt/config_proc_macro/Cargo.lock index abcf9654e5d77..ecf561f28fb6a 100644 --- a/src/tools/rustfmt/config_proc_macro/Cargo.lock +++ b/src/tools/rustfmt/config_proc_macro/Cargo.lock @@ -1,68 +1,68 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "proc-macro2" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rustfmt-config_proc_macro" -version = "0.1.2" +version = "0.2.0" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "serde", + "syn", ] [[package]] name = "serde" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" dependencies = [ - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" -"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/src/tools/rustfmt/config_proc_macro/src/lib.rs b/src/tools/rustfmt/config_proc_macro/src/lib.rs index 513018213192d..e772c53f42361 100644 --- a/src/tools/rustfmt/config_proc_macro/src/lib.rs +++ b/src/tools/rustfmt/config_proc_macro/src/lib.rs @@ -29,6 +29,8 @@ pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream { /// Used to conditionally output the TokenStream for tests that need to be run on nightly only. /// /// ```rust +/// # use rustfmt_config_proc_macro::nightly_only_test; +/// /// #[nightly_only_test] /// #[test] /// fn test_needs_nightly_rustfmt() { @@ -49,6 +51,8 @@ pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream /// Used to conditionally output the TokenStream for tests that need to be run on stable only. /// /// ```rust +/// # use rustfmt_config_proc_macro::stable_only_test; +/// /// #[stable_only_test] /// #[test] /// fn test_needs_stable_rustfmt() { diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain index 813e5e2c10fea..2640a9e0ecc28 100644 --- a/src/tools/rustfmt/rust-toolchain +++ b/src/tools/rustfmt/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-06-06" +channel = "nightly-2022-06-21" components = ["rustc-dev"] diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs index 55fd75f6de9b8..9031d29b45f7f 100644 --- a/src/tools/rustfmt/src/cargo-fmt/main.rs +++ b/src/tools/rustfmt/src/cargo-fmt/main.rs @@ -14,7 +14,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; -use clap::{CommandFactory, Parser}; +use clap::{AppSettings, CommandFactory, Parser}; #[path = "test/mod.rs"] #[cfg(test)] @@ -22,6 +22,7 @@ mod cargo_fmt_tests; #[derive(Parser)] #[clap( + global_setting(AppSettings::NoAutoVersion), bin_name = "cargo fmt", about = "This utility formats all bin and lib files of \ the current crate using rustfmt." diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index e688db1c39d7c..88a6bebb68c84 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -11,6 +11,7 @@ use crate::overflow::OverflowableItem; use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::Shape; use crate::source_map::SpanUtils; +use crate::types::rewrite_lifetime_param; use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt}; // This module is pretty messy because of the rules around closures and blocks: @@ -24,6 +25,7 @@ use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt}; // can change whether it is treated as an expression or statement. pub(crate) fn rewrite_closure( + binder: &ast::ClosureBinder, capture: ast::CaptureBy, is_async: &ast::Async, movability: ast::Movability, @@ -36,7 +38,7 @@ pub(crate) fn rewrite_closure( debug!("rewrite_closure {:?}", body); let (prefix, extra_offset) = rewrite_closure_fn_decl( - capture, is_async, movability, fn_decl, body, span, context, shape, + binder, capture, is_async, movability, fn_decl, body, span, context, shape, )?; // 1 = space between `|...|` and body. let body_shape = shape.offset_left(extra_offset)?; @@ -227,6 +229,7 @@ fn rewrite_closure_block( // Return type is (prefix, extra_offset) fn rewrite_closure_fn_decl( + binder: &ast::ClosureBinder, capture: ast::CaptureBy, asyncness: &ast::Async, movability: ast::Movability, @@ -236,6 +239,17 @@ fn rewrite_closure_fn_decl( context: &RewriteContext<'_>, shape: Shape, ) -> Option<(String, usize)> { + let binder = match binder { + ast::ClosureBinder::For { generic_params, .. } if generic_params.is_empty() => { + "for<> ".to_owned() + } + ast::ClosureBinder::For { generic_params, .. } => { + let lifetime_str = rewrite_lifetime_param(context, shape, generic_params)?; + format!("for<{lifetime_str}> ") + } + ast::ClosureBinder::NotPresent => "".to_owned(), + }; + let immovable = if movability == ast::Movability::Static { "static " } else { @@ -250,7 +264,7 @@ fn rewrite_closure_fn_decl( // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. let nested_shape = shape - .shrink_left(immovable.len() + is_async.len() + mover.len())? + .shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())? .sub_width(4)?; // 1 = | @@ -288,7 +302,7 @@ fn rewrite_closure_fn_decl( .tactic(tactic) .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{}{}{}|{}|", immovable, is_async, mover, list_str); + let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str); if !ret_str.is_empty() { if prefix.contains('\n') { @@ -312,8 +326,15 @@ pub(crate) fn rewrite_last_closure( expr: &ast::Expr, shape: Shape, ) -> Option<String> { - if let ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) = - expr.kind + if let ast::ExprKind::Closure( + ref binder, + capture, + ref is_async, + movability, + ref fn_decl, + ref body, + _, + ) = expr.kind { let body = match body.kind { ast::ExprKind::Block(ref block, _) @@ -326,7 +347,7 @@ pub(crate) fn rewrite_last_closure( _ => body, }; let (prefix, extra_offset) = rewrite_closure_fn_decl( - capture, is_async, movability, fn_decl, body, expr.span, context, shape, + binder, capture, is_async, movability, fn_decl, body, expr.span, context, shape, )?; // If the closure goes multi line before its body, do not overflow the closure. if prefix.contains('\n') { diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs index eb195b1f7628f..4d565afc1e026 100644 --- a/src/tools/rustfmt/src/comment.rs +++ b/src/tools/rustfmt/src/comment.rs @@ -730,6 +730,10 @@ impl<'a> CommentRewrite<'a> { { let mut config = self.fmt.config.clone(); config.set().wrap_comments(false); + let comment_max_width = config + .doc_comment_code_block_width() + .min(config.max_width()); + config.set().max_width(comment_max_width); if let Some(s) = crate::format_code_block(&self.code_block_buffer, &config, false) { diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs index a516952818783..f49c18d3a4603 100644 --- a/src/tools/rustfmt/src/config/mod.rs +++ b/src/tools/rustfmt/src/config/mod.rs @@ -57,6 +57,8 @@ create_config! { // Comments. macros, and strings wrap_comments: bool, false, false, "Break comments to fit on the line"; format_code_in_doc_comments: bool, false, false, "Format the code snippet in doc comments."; + doc_comment_code_block_width: usize, 100, false, "Maximum width for code snippets in doc \ + comments. No effect unless format_code_in_doc_comments = true"; comment_width: usize, 80, false, "Maximum length of comments. No effect unless wrap_comments = true"; normalize_comments: bool, false, false, "Convert /* */ comments to // comments where possible"; @@ -532,6 +534,7 @@ chain_width = 60 single_line_if_else_max_width = 50 wrap_comments = false format_code_in_doc_comments = false +doc_comment_code_block_width = 100 comment_width = 80 normalize_comments = false normalize_doc_attributes = false diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 4ccf1ca70c9d9..a7b73ba78c59e 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::cmp::min; -use std::collections::HashMap; use itertools::Itertools; use rustc_ast::token::{Delimiter, LitKind}; @@ -23,7 +22,7 @@ use crate::macros::{rewrite_macro, MacroPosition}; use crate::matches::rewrite_match; use crate::overflow::{self, IntoOverflowableItem, OverflowableItem}; use crate::pairs::{rewrite_all_pairs, rewrite_pair, PairParts}; -use crate::rewrite::{QueryId, Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::{Indent, Shape}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; @@ -54,54 +53,6 @@ pub(crate) fn format_expr( expr_type: ExprType, context: &RewriteContext<'_>, shape: Shape, -) -> Option<String> { - // when max_width is tight, we should check all possible formattings, in order to find - // if we can fit expression in the limit. Doing it recursively takes exponential time - // relative to input size, and people hit it with rustfmt takes minutes in #4476 #4867 #5128 - // By memoization of format_expr function, we format each pair of expression and shape - // only once, so worst case execution time becomes O(n*max_width^3). - if context.inside_macro() || context.is_macro_def { - // span ids are not unique in macros, so we don't memoize result of them. - return format_expr_inner(expr, expr_type, context, shape); - } - let clean; - let query_id = QueryId { - shape, - span: expr.span, - }; - if let Some(map) = context.memoize.take() { - if let Some(r) = map.get(&query_id) { - let r = r.clone(); - context.memoize.set(Some(map)); // restore map in the memoize cell for other users - return r; - } - context.memoize.set(Some(map)); - clean = false; - } else { - context.memoize.set(Some(HashMap::default())); - clean = true; // We got None, so we are the top level called function. When - // this function finishes, no one is interested in what is in the map, because - // all of them are sub expressions of this top level expression, and this is - // done. So we should clean up memoize map to save some memory. - } - - let r = format_expr_inner(expr, expr_type, context, shape); - if clean { - context.memoize.set(None); - } else { - if let Some(mut map) = context.memoize.take() { - map.insert(query_id, r.clone()); // insert the result in the memoize map - context.memoize.set(Some(map)); // so it won't be computed again - } - } - r -} - -fn format_expr_inner( - expr: &ast::Expr, - expr_type: ExprType, - context: &RewriteContext<'_>, - shape: Shape, ) -> Option<String> { skip_out_of_file_lines_range!(context, expr.span); @@ -252,11 +203,17 @@ fn format_expr_inner( Some("yield".to_string()) } } - ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) => { - closures::rewrite_closure( - capture, is_async, movability, fn_decl, body, expr.span, context, shape, - ) - } + ast::ExprKind::Closure( + ref binder, + capture, + ref is_async, + movability, + ref fn_decl, + ref body, + _, + ) => closures::rewrite_closure( + binder, capture, is_async, movability, fn_decl, body, expr.span, context, shape, + ), ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index e644ea50effd7..1dfd8a514f0bc 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use std::io::{self, Write}; -use std::rc::Rc; use std::time::{Duration, Instant}; use rustc_ast::ast; @@ -203,7 +202,6 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { self.config, &snippet_provider, self.report.clone(), - Rc::default(), ); visitor.skip_context.update_with_attrs(&self.krate.attrs); visitor.is_macro_def = is_macro_def; diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs index 559ed3917dba7..8d41c881589e5 100644 --- a/src/tools/rustfmt/src/imports.rs +++ b/src/tools/rustfmt/src/imports.rs @@ -15,7 +15,7 @@ use rustc_span::{ use crate::comment::combine_strs_with_missing_comments; use crate::config::lists::*; use crate::config::ImportGranularity; -use crate::config::{Edition, IndentStyle}; +use crate::config::{Edition, IndentStyle, Version}; use crate::lists::{ definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator, }; @@ -92,7 +92,7 @@ impl<'a> FmtVisitor<'a> { // FIXME we do a lot of allocation to make our own representation. #[derive(Clone, Eq, Hash, PartialEq)] -pub(crate) enum UseSegment { +pub(crate) enum UseSegmentKind { Ident(String, Option<String>), Slf(Option<String>), Super(Option<String>), @@ -101,6 +101,12 @@ pub(crate) enum UseSegment { List(Vec<UseTree>), } +#[derive(Clone, Eq, PartialEq)] +pub(crate) struct UseSegment { + pub(crate) kind: UseSegmentKind, + pub(crate) version: Version, +} + #[derive(Clone)] pub(crate) struct UseTree { pub(crate) path: Vec<UseSegment>, @@ -134,34 +140,38 @@ impl Spanned for UseTree { impl UseSegment { // Clone a version of self with any top-level alias removed. fn remove_alias(&self) -> UseSegment { - match *self { - UseSegment::Ident(ref s, _) => UseSegment::Ident(s.clone(), None), - UseSegment::Slf(_) => UseSegment::Slf(None), - UseSegment::Super(_) => UseSegment::Super(None), - UseSegment::Crate(_) => UseSegment::Crate(None), - _ => self.clone(), + let kind = match self.kind { + UseSegmentKind::Ident(ref s, _) => UseSegmentKind::Ident(s.clone(), None), + UseSegmentKind::Slf(_) => UseSegmentKind::Slf(None), + UseSegmentKind::Super(_) => UseSegmentKind::Super(None), + UseSegmentKind::Crate(_) => UseSegmentKind::Crate(None), + _ => return self.clone(), + }; + UseSegment { + kind, + version: self.version, } } // Check if self == other with their aliases removed. fn equal_except_alias(&self, other: &Self) -> bool { - match (self, other) { - (UseSegment::Ident(ref s1, _), UseSegment::Ident(ref s2, _)) => s1 == s2, - (UseSegment::Slf(_), UseSegment::Slf(_)) - | (UseSegment::Super(_), UseSegment::Super(_)) - | (UseSegment::Crate(_), UseSegment::Crate(_)) - | (UseSegment::Glob, UseSegment::Glob) => true, - (UseSegment::List(ref list1), UseSegment::List(ref list2)) => list1 == list2, + match (&self.kind, &other.kind) { + (UseSegmentKind::Ident(ref s1, _), UseSegmentKind::Ident(ref s2, _)) => s1 == s2, + (UseSegmentKind::Slf(_), UseSegmentKind::Slf(_)) + | (UseSegmentKind::Super(_), UseSegmentKind::Super(_)) + | (UseSegmentKind::Crate(_), UseSegmentKind::Crate(_)) + | (UseSegmentKind::Glob, UseSegmentKind::Glob) => true, + (UseSegmentKind::List(ref list1), UseSegmentKind::List(ref list2)) => list1 == list2, _ => false, } } fn get_alias(&self) -> Option<&str> { - match self { - UseSegment::Ident(_, a) - | UseSegment::Slf(a) - | UseSegment::Super(a) - | UseSegment::Crate(a) => a.as_deref(), + match &self.kind { + UseSegmentKind::Ident(_, a) + | UseSegmentKind::Slf(a) + | UseSegmentKind::Super(a) + | UseSegmentKind::Crate(a) => a.as_deref(), _ => None, } } @@ -175,19 +185,24 @@ impl UseSegment { if name.is_empty() || name == "{{root}}" { return None; } - Some(match name { - "self" => UseSegment::Slf(None), - "super" => UseSegment::Super(None), - "crate" => UseSegment::Crate(None), + let kind = match name { + "self" => UseSegmentKind::Slf(None), + "super" => UseSegmentKind::Super(None), + "crate" => UseSegmentKind::Crate(None), _ => { let mod_sep = if modsep { "::" } else { "" }; - UseSegment::Ident(format!("{}{}", mod_sep, name), None) + UseSegmentKind::Ident(format!("{}{}", mod_sep, name), None) } + }; + + Some(UseSegment { + kind, + version: context.config.version(), }) } fn contains_comment(&self) -> bool { - if let UseSegment::List(list) = self { + if let UseSegmentKind::List(list) = &self.kind { list.iter().any(|subtree| subtree.contains_comment()) } else { false @@ -254,20 +269,38 @@ impl fmt::Debug for UseTree { impl fmt::Debug for UseSegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + fmt::Display::fmt(&self.kind, f) } } impl fmt::Display for UseSegment { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.kind, f) + } +} + +impl Hash for UseSegment { + fn hash<H: Hasher>(&self, state: &mut H) { + self.kind.hash(state); + } +} + +impl fmt::Debug for UseSegmentKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for UseSegmentKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - UseSegment::Glob => write!(f, "*"), - UseSegment::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias), - UseSegment::Ident(ref s, None) => write!(f, "{}", s), - UseSegment::Slf(..) => write!(f, "self"), - UseSegment::Super(..) => write!(f, "super"), - UseSegment::Crate(..) => write!(f, "crate"), - UseSegment::List(ref list) => { + UseSegmentKind::Glob => write!(f, "*"), + UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias), + UseSegmentKind::Ident(ref s, None) => write!(f, "{}", s), + UseSegmentKind::Slf(..) => write!(f, "self"), + UseSegmentKind::Super(..) => write!(f, "super"), + UseSegmentKind::Crate(..) => write!(f, "crate"), + UseSegmentKind::List(ref list) => { write!(f, "{{")?; for (i, item) in list.iter().enumerate() { if i != 0 { @@ -411,13 +444,19 @@ impl UseTree { } } + let version = context.config.version(); + match a.kind { UseTreeKind::Glob => { // in case of a global path and the glob starts at the root, e.g., "::*" if a.prefix.segments.len() == 1 && leading_modsep { - result.path.push(UseSegment::Ident("".to_owned(), None)); + let kind = UseSegmentKind::Ident("".to_owned(), None); + result.path.push(UseSegment { kind, version }); } - result.path.push(UseSegment::Glob); + result.path.push(UseSegment { + kind: UseSegmentKind::Glob, + version, + }); } UseTreeKind::Nested(ref list) => { // Extract comments between nested use items. @@ -438,16 +477,18 @@ impl UseTree { // in case of a global path and the nested list starts at the root, // e.g., "::{foo, bar}" if a.prefix.segments.len() == 1 && leading_modsep { - result.path.push(UseSegment::Ident("".to_owned(), None)); + let kind = UseSegmentKind::Ident("".to_owned(), None); + result.path.push(UseSegment { kind, version }); } - result.path.push(UseSegment::List( + let kind = UseSegmentKind::List( list.iter() .zip(items) .map(|(t, list_item)| { Self::from_ast(context, &t.0, Some(list_item), None, None, None) }) .collect(), - )); + ); + result.path.push(UseSegment { kind, version }); } UseTreeKind::Simple(ref rename, ..) => { // If the path has leading double colons and is composed of only 2 segments, then we @@ -469,13 +510,15 @@ impl UseTree { Some(rewrite_ident(context, ident).to_owned()) } }); - let segment = match name.as_ref() { - "self" => UseSegment::Slf(alias), - "super" => UseSegment::Super(alias), - "crate" => UseSegment::Crate(alias), - _ => UseSegment::Ident(name, alias), + let kind = match name.as_ref() { + "self" => UseSegmentKind::Slf(alias), + "super" => UseSegmentKind::Super(alias), + "crate" => UseSegmentKind::Crate(alias), + _ => UseSegmentKind::Ident(name, alias), }; + let segment = UseSegment { kind, version }; + // `name` is already in result. result.path.pop(); result.path.push(segment); @@ -492,13 +535,13 @@ impl UseTree { let mut aliased_self = false; // Remove foo::{} or self without attributes. - match last { + match last.kind { _ if self.attrs.is_some() => (), - UseSegment::List(ref list) if list.is_empty() => { + UseSegmentKind::List(ref list) if list.is_empty() => { self.path = vec![]; return self; } - UseSegment::Slf(None) if self.path.is_empty() && self.visibility.is_some() => { + UseSegmentKind::Slf(None) if self.path.is_empty() && self.visibility.is_some() => { self.path = vec![]; return self; } @@ -506,15 +549,19 @@ impl UseTree { } // Normalise foo::self -> foo. - if let UseSegment::Slf(None) = last { + if let UseSegmentKind::Slf(None) = last.kind { if !self.path.is_empty() { return self; } } // Normalise foo::self as bar -> foo as bar. - if let UseSegment::Slf(_) = last { - if let Some(UseSegment::Ident(_, None)) = self.path.last() { + if let UseSegmentKind::Slf(_) = last.kind { + if let Some(UseSegment { + kind: UseSegmentKind::Ident(_, None), + .. + }) = self.path.last() + { aliased_self = true; } } @@ -522,9 +569,12 @@ impl UseTree { let mut done = false; if aliased_self { match self.path.last_mut() { - Some(UseSegment::Ident(_, ref mut old_rename)) => { + Some(UseSegment { + kind: UseSegmentKind::Ident(_, ref mut old_rename), + .. + }) => { assert!(old_rename.is_none()); - if let UseSegment::Slf(Some(rename)) = last.clone() { + if let UseSegmentKind::Slf(Some(rename)) = last.clone().kind { *old_rename = Some(rename); done = true; } @@ -538,15 +588,15 @@ impl UseTree { } // Normalise foo::{bar} -> foo::bar - if let UseSegment::List(ref list) = last { + if let UseSegmentKind::List(ref list) = last.kind { if list.len() == 1 && list[0].to_string() != "self" { normalize_sole_list = true; } } if normalize_sole_list { - match last { - UseSegment::List(list) => { + match last.kind { + UseSegmentKind::List(list) => { for seg in &list[0].path { self.path.push(seg.clone()); } @@ -557,10 +607,13 @@ impl UseTree { } // Recursively normalize elements of a list use (including sorting the list). - if let UseSegment::List(list) = last { + if let UseSegmentKind::List(list) = last.kind { let mut list = list.into_iter().map(UseTree::normalize).collect::<Vec<_>>(); list.sort(); - last = UseSegment::List(list); + last = UseSegment { + kind: UseSegmentKind::List(list), + version: last.version, + }; } self.path.push(last); @@ -620,10 +673,10 @@ impl UseTree { if self.path.is_empty() || self.contains_comment() { return vec![self]; } - match self.path.clone().last().unwrap() { - UseSegment::List(list) => { + match &self.path.clone().last().unwrap().kind { + UseSegmentKind::List(list) => { if list.len() == 1 && list[0].path.len() == 1 { - if let UseSegment::Slf(..) = list[0].path[0] { + if let UseSegmentKind::Slf(..) = list[0].path[0].kind { return vec![self]; }; } @@ -671,12 +724,15 @@ impl UseTree { /// If this tree ends in `::self`, rewrite it to `::{self}`. fn nest_trailing_self(mut self) -> UseTree { - if let Some(UseSegment::Slf(..)) = self.path.last() { + if let Some(UseSegment { + kind: UseSegmentKind::Slf(..), + .. + }) = self.path.last() + { let self_segment = self.path.pop().unwrap(); - self.path.push(UseSegment::List(vec![UseTree::from_path( - vec![self_segment], - DUMMY_SP, - )])); + let version = self_segment.version; + let kind = UseSegmentKind::List(vec![UseTree::from_path(vec![self_segment], DUMMY_SP)]); + self.path.push(UseSegment { kind, version }); } self } @@ -692,7 +748,8 @@ fn merge_rest( return None; } if a.len() != len && b.len() != len { - if let UseSegment::List(ref list) = a[len] { + let version = a[len].version; + if let UseSegmentKind::List(ref list) = a[len].kind { let mut list = list.clone(); merge_use_trees_inner( &mut list, @@ -700,7 +757,8 @@ fn merge_rest( merge_by, ); let mut new_path = b[..len].to_vec(); - new_path.push(UseSegment::List(list)); + let kind = UseSegmentKind::List(list); + new_path.push(UseSegment { kind, version }); return Some(new_path); } } else if len == 1 { @@ -709,15 +767,28 @@ fn merge_rest( } else { (&b[0], &a[1..]) }; + let kind = UseSegmentKind::Slf(common.get_alias().map(ToString::to_string)); + let version = a[0].version; let mut list = vec![UseTree::from_path( - vec![UseSegment::Slf(common.get_alias().map(ToString::to_string))], + vec![UseSegment { kind, version }], DUMMY_SP, )]; match rest { - [UseSegment::List(rest_list)] => list.extend(rest_list.clone()), + [ + UseSegment { + kind: UseSegmentKind::List(rest_list), + .. + }, + ] => list.extend(rest_list.clone()), _ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)), } - return Some(vec![b[0].clone(), UseSegment::List(list)]); + return Some(vec![ + b[0].clone(), + UseSegment { + kind: UseSegmentKind::List(list), + version, + }, + ]); } else { len -= 1; } @@ -727,7 +798,9 @@ fn merge_rest( ]; list.sort(); let mut new_path = b[..len].to_vec(); - new_path.push(UseSegment::List(list)); + let kind = UseSegmentKind::List(list); + let version = a[0].version; + new_path.push(UseSegment { kind, version }); Some(new_path) } @@ -805,19 +878,33 @@ impl PartialOrd for UseTree { } impl Ord for UseSegment { fn cmp(&self, other: &UseSegment) -> Ordering { - use self::UseSegment::*; + use self::UseSegmentKind::*; fn is_upper_snake_case(s: &str) -> bool { s.chars() .all(|c| c.is_uppercase() || c == '_' || c.is_numeric()) } - match (self, other) { - (&Slf(ref a), &Slf(ref b)) - | (&Super(ref a), &Super(ref b)) - | (&Crate(ref a), &Crate(ref b)) => a.cmp(b), - (&Glob, &Glob) => Ordering::Equal, - (&Ident(ref ia, ref aa), &Ident(ref ib, ref ab)) => { + match (&self.kind, &other.kind) { + (Slf(ref a), Slf(ref b)) + | (Super(ref a), Super(ref b)) + | (Crate(ref a), Crate(ref b)) => match (a, b) { + (Some(sa), Some(sb)) => { + if self.version == Version::Two { + sa.trim_start_matches("r#").cmp(sb.trim_start_matches("r#")) + } else { + a.cmp(b) + } + } + (_, _) => a.cmp(b), + }, + (Glob, Glob) => Ordering::Equal, + (Ident(ref pia, ref aa), Ident(ref pib, ref ab)) => { + let (ia, ib) = if self.version == Version::Two { + (pia.trim_start_matches("r#"), pib.trim_start_matches("r#")) + } else { + (pia.as_str(), pib.as_str()) + }; // snake_case < CamelCase < UPPER_SNAKE_CASE if ia.starts_with(char::is_uppercase) && ib.starts_with(char::is_lowercase) { return Ordering::Greater; @@ -835,15 +922,21 @@ impl Ord for UseSegment { if ident_ord != Ordering::Equal { return ident_ord; } - if aa.is_none() && ab.is_some() { - return Ordering::Less; - } - if aa.is_some() && ab.is_none() { - return Ordering::Greater; + match (aa, ab) { + (None, Some(_)) => Ordering::Less, + (Some(_), None) => Ordering::Greater, + (Some(aas), Some(abs)) => { + if self.version == Version::Two { + aas.trim_start_matches("r#") + .cmp(abs.trim_start_matches("r#")) + } else { + aas.cmp(abs) + } + } + (None, None) => Ordering::Equal, } - aa.cmp(ab) } - (&List(ref a), &List(ref b)) => { + (List(ref a), List(ref b)) => { for (a, b) in a.iter().zip(b.iter()) { let ord = a.cmp(b); if ord != Ordering::Equal { @@ -853,16 +946,16 @@ impl Ord for UseSegment { a.len().cmp(&b.len()) } - (&Slf(_), _) => Ordering::Less, - (_, &Slf(_)) => Ordering::Greater, - (&Super(_), _) => Ordering::Less, - (_, &Super(_)) => Ordering::Greater, - (&Crate(_), _) => Ordering::Less, - (_, &Crate(_)) => Ordering::Greater, - (&Ident(..), _) => Ordering::Less, - (_, &Ident(..)) => Ordering::Greater, - (&Glob, _) => Ordering::Less, - (_, &Glob) => Ordering::Greater, + (Slf(_), _) => Ordering::Less, + (_, Slf(_)) => Ordering::Greater, + (Super(_), _) => Ordering::Less, + (_, Super(_)) => Ordering::Greater, + (Crate(_), _) => Ordering::Less, + (_, Crate(_)) => Ordering::Greater, + (Ident(..), _) => Ordering::Less, + (_, Ident(..)) => Ordering::Greater, + (Glob, _) => Ordering::Less, + (_, Glob) => Ordering::Greater, } } } @@ -906,7 +999,7 @@ fn rewrite_nested_use_tree( } let has_nested_list = use_tree_list.iter().any(|use_segment| { use_segment.path.last().map_or(false, |last_segment| { - matches!(last_segment, UseSegment::List(..)) + matches!(last_segment.kind, UseSegmentKind::List(..)) }) }); @@ -957,17 +1050,19 @@ fn rewrite_nested_use_tree( impl Rewrite for UseSegment { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> { - Some(match self { - UseSegment::Ident(ref ident, Some(ref rename)) => format!("{} as {}", ident, rename), - UseSegment::Ident(ref ident, None) => ident.clone(), - UseSegment::Slf(Some(ref rename)) => format!("self as {}", rename), - UseSegment::Slf(None) => "self".to_owned(), - UseSegment::Super(Some(ref rename)) => format!("super as {}", rename), - UseSegment::Super(None) => "super".to_owned(), - UseSegment::Crate(Some(ref rename)) => format!("crate as {}", rename), - UseSegment::Crate(None) => "crate".to_owned(), - UseSegment::Glob => "*".to_owned(), - UseSegment::List(ref use_tree_list) => rewrite_nested_use_tree( + Some(match self.kind { + UseSegmentKind::Ident(ref ident, Some(ref rename)) => { + format!("{} as {}", ident, rename) + } + UseSegmentKind::Ident(ref ident, None) => ident.clone(), + UseSegmentKind::Slf(Some(ref rename)) => format!("self as {}", rename), + UseSegmentKind::Slf(None) => "self".to_owned(), + UseSegmentKind::Super(Some(ref rename)) => format!("super as {}", rename), + UseSegmentKind::Super(None) => "super".to_owned(), + UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {}", rename), + UseSegmentKind::Crate(None) => "crate".to_owned(), + UseSegmentKind::Glob => "*".to_owned(), + UseSegmentKind::List(ref use_tree_list) => rewrite_nested_use_tree( context, use_tree_list, // 1 = "{" and "}" @@ -1016,6 +1111,7 @@ mod test { struct Parser<'a> { input: Peekable<Chars<'a>>, + version: Version, } impl<'a> Parser<'a> { @@ -1028,34 +1124,40 @@ mod test { } fn push_segment( + &self, result: &mut Vec<UseSegment>, buf: &mut String, alias_buf: &mut Option<String>, ) { + let version = self.version; if !buf.is_empty() { let mut alias = None; swap(alias_buf, &mut alias); match buf.as_ref() { "self" => { - result.push(UseSegment::Slf(alias)); + let kind = UseSegmentKind::Slf(alias); + result.push(UseSegment { kind, version }); *buf = String::new(); *alias_buf = None; } "super" => { - result.push(UseSegment::Super(alias)); + let kind = UseSegmentKind::Super(alias); + result.push(UseSegment { kind, version }); *buf = String::new(); *alias_buf = None; } "crate" => { - result.push(UseSegment::Crate(alias)); + let kind = UseSegmentKind::Crate(alias); + result.push(UseSegment { kind, version }); *buf = String::new(); *alias_buf = None; } _ => { let mut name = String::new(); swap(buf, &mut name); - result.push(UseSegment::Ident(name, alias)); + let kind = UseSegmentKind::Ident(name, alias); + result.push(UseSegment { kind, version }); } } } @@ -1070,21 +1172,29 @@ mod test { '{' => { assert!(buf.is_empty()); self.bump(); - result.push(UseSegment::List(self.parse_list())); + let kind = UseSegmentKind::List(self.parse_list()); + result.push(UseSegment { + kind, + version: self.version, + }); self.eat('}'); } '*' => { assert!(buf.is_empty()); self.bump(); - result.push(UseSegment::Glob); + let kind = UseSegmentKind::Glob; + result.push(UseSegment { + kind, + version: self.version, + }); } ':' => { self.bump(); self.eat(':'); - Self::push_segment(&mut result, &mut buf, &mut alias_buf); + self.push_segment(&mut result, &mut buf, &mut alias_buf); } '}' | ',' => { - Self::push_segment(&mut result, &mut buf, &mut alias_buf); + self.push_segment(&mut result, &mut buf, &mut alias_buf); return UseTree { path: result, span: DUMMY_SP, @@ -1110,7 +1220,7 @@ mod test { } } } - Self::push_segment(&mut result, &mut buf, &mut alias_buf); + self.push_segment(&mut result, &mut buf, &mut alias_buf); UseTree { path: result, span: DUMMY_SP, @@ -1136,6 +1246,7 @@ mod test { let mut parser = Parser { input: s.chars().peekable(), + version: Version::One, }; parser.parse_in_list() } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index bab881f4b4e8d..8f35068e35f04 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -148,7 +148,7 @@ impl<'a> Item<'a> { Item { unsafety: fm.unsafety, abi: format_extern( - ast::Extern::from_abi(fm.abi), + ast::Extern::from_abi(fm.abi, DUMMY_SP), config.force_explicit_abi(), true, ), diff --git a/src/tools/rustfmt/src/reorder.rs b/src/tools/rustfmt/src/reorder.rs index 8ae297de25bc2..9e4a668aa4930 100644 --- a/src/tools/rustfmt/src/reorder.rs +++ b/src/tools/rustfmt/src/reorder.rs @@ -12,7 +12,7 @@ use rustc_ast::ast; use rustc_span::{symbol::sym, Span}; use crate::config::{Config, GroupImportsTactic}; -use crate::imports::{normalize_use_trees_with_granularity, UseSegment, UseTree}; +use crate::imports::{normalize_use_trees_with_granularity, UseSegmentKind, UseTree}; use crate::items::{is_mod_decl, rewrite_extern_crate, rewrite_mod}; use crate::lists::{itemize_list, write_list, ListFormatting, ListItem}; use crate::rewrite::RewriteContext; @@ -182,16 +182,16 @@ fn group_imports(uts: Vec<UseTree>) -> Vec<Vec<UseTree>> { external_imports.push(ut); continue; } - match &ut.path[0] { - UseSegment::Ident(id, _) => match id.as_ref() { + match &ut.path[0].kind { + UseSegmentKind::Ident(id, _) => match id.as_ref() { "std" | "alloc" | "core" => std_imports.push(ut), _ => external_imports.push(ut), }, - UseSegment::Slf(_) | UseSegment::Super(_) | UseSegment::Crate(_) => { + UseSegmentKind::Slf(_) | UseSegmentKind::Super(_) | UseSegmentKind::Crate(_) => { local_imports.push(ut) } // These are probably illegal here - UseSegment::Glob | UseSegment::List(_) => external_imports.push(ut), + UseSegmentKind::Glob | UseSegmentKind::List(_) => external_imports.push(ut), } } diff --git a/src/tools/rustfmt/src/rewrite.rs b/src/tools/rustfmt/src/rewrite.rs index f97df70cc6a7b..4a3bd129d16f5 100644 --- a/src/tools/rustfmt/src/rewrite.rs +++ b/src/tools/rustfmt/src/rewrite.rs @@ -12,7 +12,6 @@ use crate::shape::Shape; use crate::skip::SkipContext; use crate::visitor::SnippetProvider; use crate::FormatReport; -use rustc_data_structures::stable_map::FxHashMap; pub(crate) trait Rewrite { /// Rewrite self into shape. @@ -25,22 +24,10 @@ impl<T: Rewrite> Rewrite for ptr::P<T> { } } -#[derive(Clone, PartialEq, Eq, Hash)] -pub(crate) struct QueryId { - pub(crate) shape: Shape, - pub(crate) span: Span, -} - -// We use Option<HashMap> instead of HashMap, because in case of `None` -// the function clean the memoize map, but it doesn't clean when -// there is `Some(empty)`, so they are different. -pub(crate) type Memoize = Rc<Cell<Option<FxHashMap<QueryId, Option<String>>>>>; - #[derive(Clone)] pub(crate) struct RewriteContext<'a> { pub(crate) parse_sess: &'a ParseSess, pub(crate) config: &'a Config, - pub(crate) memoize: Memoize, pub(crate) inside_macro: Rc<Cell<bool>>, // Force block indent style even if we are using visual indent style. pub(crate) use_block: Cell<bool>, diff --git a/src/tools/rustfmt/src/shape.rs b/src/tools/rustfmt/src/shape.rs index b3f785a9470ee..4376fd12b5260 100644 --- a/src/tools/rustfmt/src/shape.rs +++ b/src/tools/rustfmt/src/shape.rs @@ -4,7 +4,7 @@ use std::ops::{Add, Sub}; use crate::Config; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug)] pub(crate) struct Indent { // Width of the block indent, in characters. Must be a multiple of // Config::tab_spaces. @@ -139,7 +139,7 @@ impl Sub<usize> for Indent { // 8096 is close enough to infinite for rustfmt. const INFINITE_SHAPE_WIDTH: usize = 8096; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug)] pub(crate) struct Shape { pub(crate) width: usize, // The current indentation of code. diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 64a201e45ddd4..2627886db109d 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1067,7 +1067,7 @@ pub(crate) fn can_be_overflowed_type( } /// Returns `None` if there is no `LifetimeDef` in the given generic parameters. -fn rewrite_lifetime_param( +pub(crate) fn rewrite_lifetime_param( context: &RewriteContext<'_>, shape: Shape, generic_params: &[ast::GenericParam], diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 58fd95c656e79..cd852855602e8 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -138,8 +138,8 @@ pub(crate) fn format_extern( ) -> Cow<'static, str> { let abi = match ext { ast::Extern::None => "Rust".to_owned(), - ast::Extern::Implicit => "C".to_owned(), - ast::Extern::Explicit(abi) => abi.symbol_unescaped.to_string(), + ast::Extern::Implicit(_) => "C".to_owned(), + ast::Extern::Explicit(abi, _) => abi.symbol_unescaped.to_string(), }; if abi == "Rust" && !is_mod { @@ -479,7 +479,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Binary(_, _, ref expr) | ast::ExprKind::Index(_, ref expr) | ast::ExprKind::Unary(_, ref expr) - | ast::ExprKind::Closure(_, _, _, _, ref expr, _) + | ast::ExprKind::Closure(_, _, _, _, _, ref expr, _) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr), // This can only be a string lit diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 3ff56d52f92d6..9a0e0752c12f5 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -17,7 +17,7 @@ use crate::items::{ use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition}; use crate::modules::Module; use crate::parse::session::ParseSess; -use crate::rewrite::{Memoize, Rewrite, RewriteContext}; +use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::{Indent, Shape}; use crate::skip::{is_skip_attr, SkipContext}; use crate::source_map::{LineRangeUtils, SpanUtils}; @@ -71,7 +71,6 @@ impl SnippetProvider { pub(crate) struct FmtVisitor<'a> { parent_context: Option<&'a RewriteContext<'a>>, - pub(crate) memoize: Memoize, pub(crate) parse_sess: &'a ParseSess, pub(crate) buffer: String, pub(crate) last_pos: BytePos, @@ -759,7 +758,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ctx.config, ctx.snippet_provider, ctx.report.clone(), - ctx.memoize.clone(), ); visitor.skip_context.update(ctx.skip_context.clone()); visitor.set_parent_context(ctx); @@ -771,12 +769,10 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { config: &'a Config, snippet_provider: &'a SnippetProvider, report: FormatReport, - memoize: Memoize, ) -> FmtVisitor<'a> { FmtVisitor { parent_context: None, parse_sess: parse_session, - memoize, buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2), last_pos: BytePos(0), block_indent: Indent::empty(), @@ -999,7 +995,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { RewriteContext { parse_sess: self.parse_sess, config: self.config, - memoize: self.memoize.clone(), inside_macro: Rc::new(Cell::new(false)), use_block: Cell::new(false), is_if_else_block: Cell::new(false), diff --git a/src/tools/rustfmt/tests/source/closure.rs b/src/tools/rustfmt/tests/source/closure.rs index e93cc3fb40f59..b2d28b305d0ad 100644 --- a/src/tools/rustfmt/tests/source/closure.rs +++ b/src/tools/rustfmt/tests/source/closure.rs @@ -51,6 +51,16 @@ fn main() { "--emit=dep-info" } else { a } }); + + for<> || -> () {}; + for< >|| -> () {}; + for< +> || -> () {}; + +for< 'a + ,'b, +'c > |_: &'a (), _: &'b (), _: &'c ()| -> () {}; + } fn issue311() { diff --git a/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/100.rs b/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/100.rs new file mode 100644 index 0000000000000..515780761670c --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/100.rs @@ -0,0 +1,16 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-doc_comment_code_block_width: 100 + +/// ```rust +/// impl Test { +/// pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { +/// Self::from_bytes_manual_slice(v, 0, v.len() ) +/// } +/// } +/// ``` + +impl Test { + pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { + Self::from_bytes_manual_slice(v, 0, v.len() ) + } +} diff --git a/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/100_greater_max_width.rs b/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/100_greater_max_width.rs new file mode 100644 index 0000000000000..96505c69714e5 --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/100_greater_max_width.rs @@ -0,0 +1,17 @@ +// rustfmt-max_width: 50 +// rustfmt-format_code_in_doc_comments: true +// rustfmt-doc_comment_code_block_width: 100 + +/// ```rust +/// impl Test { +/// pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { +/// Self::from_bytes_manual_slice(v, 0, v.len() ) +/// } +/// } +/// ``` + +impl Test { + pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { + Self::from_bytes_manual_slice(v, 0, v.len() ) + } +} diff --git a/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/50.rs b/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/50.rs new file mode 100644 index 0000000000000..2c6307951c84e --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/doc_comment_code_block_width/50.rs @@ -0,0 +1,16 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-doc_comment_code_block_width: 50 + +/// ```rust +/// impl Test { +/// pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { +/// Self::from_bytes_manual_slice(v, 0, v.len() ) +/// } +/// } +/// ``` + +impl Test { + pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { + Self::from_bytes_manual_slice(v, 0, v.len() ) + } +} diff --git a/src/tools/rustfmt/tests/source/imports_raw_identifiers/version_One.rs b/src/tools/rustfmt/tests/source/imports_raw_identifiers/version_One.rs new file mode 100644 index 0000000000000..bc4b5b135696a --- /dev/null +++ b/src/tools/rustfmt/tests/source/imports_raw_identifiers/version_One.rs @@ -0,0 +1,5 @@ +// rustfmt-version:One + +use websocket::client::ClientBuilder; +use websocket::r#async::futures::Stream; +use websocket::result::WebSocketError; diff --git a/src/tools/rustfmt/tests/source/imports_raw_identifiers/version_Two.rs b/src/tools/rustfmt/tests/source/imports_raw_identifiers/version_Two.rs new file mode 100644 index 0000000000000..88e7fbd01ca6e --- /dev/null +++ b/src/tools/rustfmt/tests/source/imports_raw_identifiers/version_Two.rs @@ -0,0 +1,5 @@ +// rustfmt-version:Two + +use websocket::client::ClientBuilder; +use websocket::r#async::futures::Stream; +use websocket::result::WebSocketError; diff --git a/src/tools/rustfmt/tests/source/performance/issue-4476.rs b/src/tools/rustfmt/tests/source/performance/issue-4476.rs deleted file mode 100644 index 8da3f19b62d60..0000000000000 --- a/src/tools/rustfmt/tests/source/performance/issue-4476.rs +++ /dev/null @@ -1,638 +0,0 @@ -use super::SemverParser; - -#[allow(dead_code, non_camel_case_types)] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Rule { - EOI, - range_set, - logical_or, - range, - empty, - hyphen, - simple, - primitive, - primitive_op, - partial, - xr, - xr_op, - nr, - tilde, - caret, - qualifier, - parts, - part, - space, -} -#[allow(clippy::all)] -impl ::pest::Parser<Rule> for SemverParser { - fn parse<'i>( - rule: Rule, - input: &'i str, - ) -> ::std::result::Result<::pest::iterators::Pairs<'i, Rule>, ::pest::error::Error<Rule>> { - mod rules { - pub mod hidden { - use super::super::Rule; - #[inline] - #[allow(dead_code, non_snake_case, unused_variables)] - pub fn skip( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - Ok(state) - } - } - pub mod visible { - use super::super::Rule; - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn range_set( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::range_set, |state| { - state.sequence(|state| { - self::SOI(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::range(state)) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .sequence(|state| { - self::logical_or(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::range(state)) - }) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| { - state.sequence(|state| { - self::logical_or(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::range(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::EOI(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn logical_or( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::logical_or, |state| { - state.sequence(|state| { - state - .sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| state.match_string("||")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn range( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::range, |state| { - self::hyphen(state) - .or_else(|state| { - state.sequence(|state| { - self::simple(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .sequence(|state| { - state - .optional(|state| state.match_string(",")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::simple(state)) - }) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| { - state.sequence(|state| { - state - .optional(|state| state.match_string(",")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::simple(state)) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - .or_else(|state| self::empty(state)) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn empty( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::empty, |state| state.match_string("")) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn hyphen( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::hyphen, |state| { - state.sequence(|state| { - self::partial(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| state.match_string("-")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn simple( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::simple, |state| { - self::primitive(state) - .or_else(|state| self::partial(state)) - .or_else(|state| self::tilde(state)) - .or_else(|state| self::caret(state)) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn primitive( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::primitive, |state| { - state.sequence(|state| { - self::primitive_op(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn primitive_op( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::primitive_op, |state| { - state - .match_string("<=") - .or_else(|state| state.match_string(">=")) - .or_else(|state| state.match_string(">")) - .or_else(|state| state.match_string("<")) - .or_else(|state| state.match_string("=")) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn partial( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::partial, |state| { - state.sequence(|state| { - self::xr(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.optional(|state| { - state.sequence(|state| { - state - .match_string(".") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::xr(state)) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.optional(|state| { - state.sequence(|state| { - state - .match_string(".") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::xr(state)) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| state.optional(|state| self::qualifier(state))) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn xr( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::xr, |state| { - self::xr_op(state).or_else(|state| self::nr(state)) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn xr_op( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::xr_op, |state| { - state - .match_string("x") - .or_else(|state| state.match_string("X")) - .or_else(|state| state.match_string("*")) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn nr( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::nr, |state| { - state.match_string("0").or_else(|state| { - state.sequence(|state| { - state - .match_range('1'..'9') - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state.match_range('0'..'9').and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| state.match_range('0'..'9')) - }) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn tilde( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::tilde, |state| { - state.sequence(|state| { - state - .match_string("~>") - .or_else(|state| state.match_string("~")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn caret( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::caret, |state| { - state.sequence(|state| { - state - .match_string("^") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn qualifier( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::qualifier, |state| { - state.sequence(|state| { - state - .match_string("-") - .or_else(|state| state.match_string("+")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::parts(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn parts( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::parts, |state| { - state.sequence(|state| { - self::part(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .sequence(|state| { - state - .match_string(".") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::part(state)) - }) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| { - state.sequence(|state| { - state - .match_string(".") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::part(state)) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn part( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::part, |state| { - self::nr(state).or_else(|state| { - state.sequence(|state| { - state - .match_string("-") - .or_else(|state| state.match_range('0'..'9')) - .or_else(|state| state.match_range('A'..'Z')) - .or_else(|state| state.match_range('a'..'z')) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .match_string("-") - .or_else(|state| state.match_range('0'..'9')) - .or_else(|state| state.match_range('A'..'Z')) - .or_else(|state| state.match_range('a'..'z')) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then(|state| { - state - .match_string("-") - .or_else(|state| state.match_range('0'..'9')) - .or_else(|state| state.match_range('A'..'Z')) - .or_else(|state| state.match_range('a'..'z')) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn space( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state - .match_string(" ") - .or_else(|state| state.match_string("\t")) - } - #[inline] - #[allow(dead_code, non_snake_case, unused_variables)] - pub fn EOI( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::EOI, |state| state.end_of_input()) - } - #[inline] - #[allow(dead_code, non_snake_case, unused_variables)] - pub fn SOI( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.start_of_input() - } - } - pub use self::visible::*; - } - ::pest::state(input, |state| match rule { - Rule::range_set => rules::range_set(state), - Rule::logical_or => rules::logical_or(state), - Rule::range => rules::range(state), - Rule::empty => rules::empty(state), - Rule::hyphen => rules::hyphen(state), - Rule::simple => rules::simple(state), - Rule::primitive => rules::primitive(state), - Rule::primitive_op => rules::primitive_op(state), - Rule::partial => rules::partial(state), - Rule::xr => rules::xr(state), - Rule::xr_op => rules::xr_op(state), - Rule::nr => rules::nr(state), - Rule::tilde => rules::tilde(state), - Rule::caret => rules::caret(state), - Rule::qualifier => rules::qualifier(state), - Rule::parts => rules::parts(state), - Rule::part => rules::part(state), - Rule::space => rules::space(state), - Rule::EOI => rules::EOI(state), - }) - } -} \ No newline at end of file diff --git a/src/tools/rustfmt/tests/source/performance/issue-5128.rs b/src/tools/rustfmt/tests/source/performance/issue-5128.rs deleted file mode 100644 index 3adce49601c0c..0000000000000 --- a/src/tools/rustfmt/tests/source/performance/issue-5128.rs +++ /dev/null @@ -1,5127 +0,0 @@ - -fn takes_a_long_time_to_rustfmt() { - let inner_cte = vec![Node { - node: Some(node::Node::CommonTableExpr(Box::new(CommonTableExpr { - ctename: String::from("ranked_by_age_within_key"), - aliascolnames: vec![], - ctematerialized: CteMaterialize::Default as i32, - ctequery: Some(Box::new(Node { - node: Some(node::Node::SelectStmt(Box::new(SelectStmt { - distinct_clause: vec![], - into_clause: None, - target_list: vec![ - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from(""), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::AStar(AStar{})) - }], - location: 80 - })) - })), - location: 80 - }))) - }, - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from("rank_in_key"), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::FuncCall(Box::new(FuncCall { - funcname: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("row_number") - })) - }], - args: vec![], - agg_order: vec![], - agg_filter: None, - agg_within_group: false, - agg_star: false, - agg_distinct: false, - func_variadic: false, - over: Some(Box::new(WindowDef { - name: String::from(""), - refname: String::from(""), - partition_clause: vec![ - Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("synthetic_key") - })) - }], location: 123 - })) - }], order_clause: vec![Node { - node: Some(node::Node::SortBy(Box::new(SortBy { - node: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("logical_timestamp") - })) - }], location: 156 - })) - })), - sortby_dir: SortByDir::SortbyDesc as i32, - sortby_nulls: SortByNulls::SortbyNullsDefault as i32, - use_op: vec![], - location: -1 - }))) - }], frame_options: 1058, start_offset: None, end_offset: None, location: 109 - })), - location: 91 - }))) - })), - location: 91 - }))) - }], - from_clause: vec![Node { - node: Some(node::Node::RangeVar(RangeVar { - catalogname: String::from(""), schemaname: String::from("_supertables"), relname: String::from("9999-9999-9999"), inh: true, relpersistence: String::from("p"), alias: None, location: 206 - })) - }], - where_clause: Some(Box::new(Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("<=") - })) - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("logical_timestamp") - })) - }], - location: 250 - })) - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new(AConst { - val: Some(Box::new(Node { - node: Some(node::Node::Integer(Integer { - ival: 9000 - })) - })), - location: 271 - }))) - })), - location: 268 - }))) - })), - group_clause: vec![], - having_clause: None, - window_clause: vec![], - values_lists: vec![], - sort_clause: vec![], - limit_offset: None, - limit_count: None, - limit_option: LimitOption::Default as i32, - locking_clause: vec![], - with_clause: None, - op: SetOperation::SetopNone as i32, - all: false, - larg: None, - rarg: None - }))), - })), - location: 29, - cterecursive: false, - cterefcount: 0, - ctecolnames: vec![], - ctecoltypes: vec![], - ctecoltypmods: vec![], - ctecolcollations: vec![], - }))), - }]; - let outer_cte = vec![Node { - node: Some(node::Node::CommonTableExpr(Box::new(CommonTableExpr { - ctename: String::from("table_name"), - aliascolnames: vec![], - ctematerialized: CteMaterialize::Default as i32, - ctequery: Some(Box::new(Node { - node: Some(node::Node::SelectStmt(Box::new(SelectStmt { - distinct_clause: vec![], - into_clause: None, - target_list: vec![ - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from("column1"), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("c1"), - })), - }], - location: 301, - })), - })), - location: 301, - }))), - }, - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from("column2"), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("c2"), - })), - }], - location: 324, - })), - })), - location: 324, - }))), - }, - ], - from_clause: vec![Node { - node: Some(node::Node::RangeVar(RangeVar { - catalogname: String::from(""), - schemaname: String::from(""), - relname: String::from("ranked_by_age_within_key"), - inh: true, - relpersistence: String::from("p"), - alias: None, - location: 347, - })), - }], - where_clause: Some(Box::new(Node { - node: Some(node::Node::BoolExpr(Box::new(BoolExpr { - xpr: None, - boolop: BoolExprType::AndExpr as i32, - args: vec![ - Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("="), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String( - String2 { - str: String::from("rank_in_key"), - }, - )), - }], - location: 382, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new(AConst { - val: Some(Box::new(Node { - node: Some(node::Node::Integer( - Integer { ival: 1 }, - )), - })), - location: 396, - }))), - })), - location: 394, - }))), - }, - Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("="), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String( - String2 { - str: String::from("is_deleted"), - }, - )), - }], - location: 402, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::TypeCast(Box::new( - TypeCast { - arg: Some(Box::new(Node { - node: Some(node::Node::AConst( - Box::new(AConst { - val: Some(Box::new(Node { - node: Some( - node::Node::String( - String2 { - str: - String::from( - "f", - ), - }, - ), - ), - })), - location: 415, - }), - )), - })), - type_name: Some(TypeName { - names: vec![ - Node { - node: Some(node::Node::String( - String2 { - str: String::from( - "pg_catalog", - ), - }, - )), - }, - Node { - node: Some(node::Node::String( - String2 { - str: String::from( - "bool", - ), - }, - )), - }, - ], - type_oid: 0, - setof: false, - pct_type: false, - typmods: vec![], - typemod: -1, - array_bounds: vec![], - location: -1, - }), - location: -1, - }, - ))), - })), - location: 413, - }))), - }, - ], - location: 398, - }))), - })), - group_clause: vec![], - having_clause: None, - window_clause: vec![], - values_lists: vec![], - sort_clause: vec![], - limit_offset: None, - limit_count: None, - limit_option: LimitOption::Default as i32, - locking_clause: vec![], - with_clause: Some(WithClause { - ctes: inner_cte, - recursive: false, - location: 24, - }), - op: SetOperation::SetopNone as i32, - all: false, - larg: None, - rarg: None, - }))), - })), - location: 5, - cterecursive: false, - cterefcount: 0, - ctecolnames: vec![], - ctecoltypes: vec![], - ctecoltypmods: vec![], - ctecolcollations: vec![], - }))), - }]; - let expected_result = ParseResult { - version: 130003, - stmts: vec![RawStmt { - stmt: Some(Box::new(Node { - node: Some(node::Node::SelectStmt(Box::new(SelectStmt { - distinct_clause: vec![], - into_clause: None, - - target_list: vec![Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from(""), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("column1"), - })), - }], - location: 430, - })), - })), - location: 430, - }))), - }], - from_clause: vec![Node { - node: Some(node::Node::RangeVar(RangeVar { - catalogname: String::from(""), - schemaname: String::from(""), - relname: String::from("table_name"), - inh: true, - relpersistence: String::from("p"), - alias: None, - location: 443, - })), - }], - where_clause: Some(Box::new(Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from(">"), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("column2"), - })), - }], - location: 460, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new(AConst { - val: Some(Box::new(Node { - node: Some(node::Node::Integer(Integer { - ival: 9000, - })), - })), - location: 470, - }))), - })), - location: 468, - }))), - })), - group_clause: vec![], - having_clause: None, - window_clause: vec![], - values_lists: vec![], - sort_clause: vec![], - limit_offset: None, - limit_count: None, - limit_option: LimitOption::Default as i32, - locking_clause: vec![], - with_clause: Some(WithClause { - ctes: outer_cte, - recursive: false, - location: 0, - }), - op: SetOperation::SetopNone as i32, - all: false, - larg: None, - rarg: None, - }))), - })), - stmt_location: 0, - stmt_len: 0, - }], - }; - -} -#[derive(Clone, PartialEq)] -pub struct ParseResult { - - pub version: i32, - - pub stmts: Vec<RawStmt>, -} -#[derive(Clone, PartialEq)] -pub struct ScanResult { - - pub version: i32, - - pub tokens: Vec<ScanToken>, -} -#[derive(Clone, PartialEq)] -pub struct Node { - pub node: ::core::option::Option<node::Node>, -} -/// Nested message and enum types in `Node`. -pub mod node { - #[derive(Clone, PartialEq)] - pub enum Node { - - Alias(super::Alias), - - RangeVar(super::RangeVar), - - TableFunc(Box<super::TableFunc>), - - Expr(super::Expr), - - Var(Box<super::Var>), - - Param(Box<super::Param>), - - Aggref(Box<super::Aggref>), - - GroupingFunc(Box<super::GroupingFunc>), - - WindowFunc(Box<super::WindowFunc>), - - SubscriptingRef(Box<super::SubscriptingRef>), - - FuncExpr(Box<super::FuncExpr>), - - NamedArgExpr(Box<super::NamedArgExpr>), - - OpExpr(Box<super::OpExpr>), - - DistinctExpr(Box<super::DistinctExpr>), - - NullIfExpr(Box<super::NullIfExpr>), - - ScalarArrayOpExpr(Box<super::ScalarArrayOpExpr>), - - BoolExpr(Box<super::BoolExpr>), - - SubLink(Box<super::SubLink>), - - SubPlan(Box<super::SubPlan>), - - AlternativeSubPlan(Box<super::AlternativeSubPlan>), - - FieldSelect(Box<super::FieldSelect>), - - FieldStore(Box<super::FieldStore>), - - RelabelType(Box<super::RelabelType>), - - CoerceViaIo(Box<super::CoerceViaIo>), - - ArrayCoerceExpr(Box<super::ArrayCoerceExpr>), - - ConvertRowtypeExpr(Box<super::ConvertRowtypeExpr>), - - CollateExpr(Box<super::CollateExpr>), - - CaseExpr(Box<super::CaseExpr>), - - CaseWhen(Box<super::CaseWhen>), - - CaseTestExpr(Box<super::CaseTestExpr>), - - ArrayExpr(Box<super::ArrayExpr>), - - RowExpr(Box<super::RowExpr>), - - RowCompareExpr(Box<super::RowCompareExpr>), - - CoalesceExpr(Box<super::CoalesceExpr>), - - MinMaxExpr(Box<super::MinMaxExpr>), - - SqlvalueFunction(Box<super::SqlValueFunction>), - - XmlExpr(Box<super::XmlExpr>), - - NullTest(Box<super::NullTest>), - - BooleanTest(Box<super::BooleanTest>), - - CoerceToDomain(Box<super::CoerceToDomain>), - - CoerceToDomainValue(Box<super::CoerceToDomainValue>), - - SetToDefault(Box<super::SetToDefault>), - - CurrentOfExpr(Box<super::CurrentOfExpr>), - - NextValueExpr(Box<super::NextValueExpr>), - - InferenceElem(Box<super::InferenceElem>), - - TargetEntry(Box<super::TargetEntry>), - - RangeTblRef(super::RangeTblRef), - - JoinExpr(Box<super::JoinExpr>), - - FromExpr(Box<super::FromExpr>), - - OnConflictExpr(Box<super::OnConflictExpr>), - - IntoClause(Box<super::IntoClause>), - - RawStmt(Box<super::RawStmt>), - - Query(Box<super::Query>), - - InsertStmt(Box<super::InsertStmt>), - - DeleteStmt(Box<super::DeleteStmt>), - - UpdateStmt(Box<super::UpdateStmt>), - - SelectStmt(Box<super::SelectStmt>), - - AlterTableStmt(super::AlterTableStmt), - - AlterTableCmd(Box<super::AlterTableCmd>), - - AlterDomainStmt(Box<super::AlterDomainStmt>), - - SetOperationStmt(Box<super::SetOperationStmt>), - - GrantStmt(super::GrantStmt), - - GrantRoleStmt(super::GrantRoleStmt), - - AlterDefaultPrivilegesStmt(super::AlterDefaultPrivilegesStmt), - - ClosePortalStmt(super::ClosePortalStmt), - - ClusterStmt(super::ClusterStmt), - - CopyStmt(Box<super::CopyStmt>), - - CreateStmt(super::CreateStmt), - - DefineStmt(super::DefineStmt), - - DropStmt(super::DropStmt), - - TruncateStmt(super::TruncateStmt), - - CommentStmt(Box<super::CommentStmt>), - - FetchStmt(super::FetchStmt), - - IndexStmt(Box<super::IndexStmt>), - - CreateFunctionStmt(super::CreateFunctionStmt), - - AlterFunctionStmt(super::AlterFunctionStmt), - - DoStmt(super::DoStmt), - - RenameStmt(Box<super::RenameStmt>), - - RuleStmt(Box<super::RuleStmt>), - - NotifyStmt(super::NotifyStmt), - - ListenStmt(super::ListenStmt), - - UnlistenStmt(super::UnlistenStmt), - - TransactionStmt(super::TransactionStmt), - - ViewStmt(Box<super::ViewStmt>), - - LoadStmt(super::LoadStmt), - - CreateDomainStmt(Box<super::CreateDomainStmt>), - - CreatedbStmt(super::CreatedbStmt), - - DropdbStmt(super::DropdbStmt), - - VacuumStmt(super::VacuumStmt), - - ExplainStmt(Box<super::ExplainStmt>), - - CreateTableAsStmt(Box<super::CreateTableAsStmt>), - - CreateSeqStmt(super::CreateSeqStmt), - - AlterSeqStmt(super::AlterSeqStmt), - - VariableSetStmt(super::VariableSetStmt), - - VariableShowStmt(super::VariableShowStmt), - - DiscardStmt(super::DiscardStmt), - - CreateTrigStmt(Box<super::CreateTrigStmt>), - - CreatePlangStmt(super::CreatePLangStmt), - - CreateRoleStmt(super::CreateRoleStmt), - - AlterRoleStmt(super::AlterRoleStmt), - - DropRoleStmt(super::DropRoleStmt), - - LockStmt(super::LockStmt), - - ConstraintsSetStmt(super::ConstraintsSetStmt), - - ReindexStmt(super::ReindexStmt), - - CheckPointStmt(super::CheckPointStmt), - - CreateSchemaStmt(super::CreateSchemaStmt), - - AlterDatabaseStmt(super::AlterDatabaseStmt), - - AlterDatabaseSetStmt(super::AlterDatabaseSetStmt), - - AlterRoleSetStmt(super::AlterRoleSetStmt), - - CreateConversionStmt(super::CreateConversionStmt), - - CreateCastStmt(super::CreateCastStmt), - - CreateOpClassStmt(super::CreateOpClassStmt), - - CreateOpFamilyStmt(super::CreateOpFamilyStmt), - - AlterOpFamilyStmt(super::AlterOpFamilyStmt), - - PrepareStmt(Box<super::PrepareStmt>), - - ExecuteStmt(super::ExecuteStmt), - - DeallocateStmt(super::DeallocateStmt), - - DeclareCursorStmt(Box<super::DeclareCursorStmt>), - - CreateTableSpaceStmt(super::CreateTableSpaceStmt), - - DropTableSpaceStmt(super::DropTableSpaceStmt), - - AlterObjectDependsStmt(Box<super::AlterObjectDependsStmt>), - - AlterObjectSchemaStmt(Box<super::AlterObjectSchemaStmt>), - - AlterOwnerStmt(Box<super::AlterOwnerStmt>), - - AlterOperatorStmt(super::AlterOperatorStmt), - - AlterTypeStmt(super::AlterTypeStmt), - - DropOwnedStmt(super::DropOwnedStmt), - - ReassignOwnedStmt(super::ReassignOwnedStmt), - - CompositeTypeStmt(super::CompositeTypeStmt), - - CreateEnumStmt(super::CreateEnumStmt), - - CreateRangeStmt(super::CreateRangeStmt), - - AlterEnumStmt(super::AlterEnumStmt), - - AlterTsdictionaryStmt(super::AlterTsDictionaryStmt), - - AlterTsconfigurationStmt(super::AlterTsConfigurationStmt), - - CreateFdwStmt(super::CreateFdwStmt), - - AlterFdwStmt(super::AlterFdwStmt), - - CreateForeignServerStmt(super::CreateForeignServerStmt), - - AlterForeignServerStmt(super::AlterForeignServerStmt), - - CreateUserMappingStmt(super::CreateUserMappingStmt), - - AlterUserMappingStmt(super::AlterUserMappingStmt), - - DropUserMappingStmt(super::DropUserMappingStmt), - - AlterTableSpaceOptionsStmt(super::AlterTableSpaceOptionsStmt), - - AlterTableMoveAllStmt(super::AlterTableMoveAllStmt), - - SecLabelStmt(Box<super::SecLabelStmt>), - - CreateForeignTableStmt(super::CreateForeignTableStmt), - - ImportForeignSchemaStmt(super::ImportForeignSchemaStmt), - - CreateExtensionStmt(super::CreateExtensionStmt), - - AlterExtensionStmt(super::AlterExtensionStmt), - - AlterExtensionContentsStmt(Box<super::AlterExtensionContentsStmt>), - - CreateEventTrigStmt(super::CreateEventTrigStmt), - - AlterEventTrigStmt(super::AlterEventTrigStmt), - - RefreshMatViewStmt(super::RefreshMatViewStmt), - - ReplicaIdentityStmt(super::ReplicaIdentityStmt), - - AlterSystemStmt(super::AlterSystemStmt), - - CreatePolicyStmt(Box<super::CreatePolicyStmt>), - - AlterPolicyStmt(Box<super::AlterPolicyStmt>), - - CreateTransformStmt(super::CreateTransformStmt), - - CreateAmStmt(super::CreateAmStmt), - - CreatePublicationStmt(super::CreatePublicationStmt), - - AlterPublicationStmt(super::AlterPublicationStmt), - - CreateSubscriptionStmt(super::CreateSubscriptionStmt), - - AlterSubscriptionStmt(super::AlterSubscriptionStmt), - - DropSubscriptionStmt(super::DropSubscriptionStmt), - - CreateStatsStmt(super::CreateStatsStmt), - - AlterCollationStmt(super::AlterCollationStmt), - - CallStmt(Box<super::CallStmt>), - - AlterStatsStmt(super::AlterStatsStmt), - - AExpr(Box<super::AExpr>), - - ColumnRef(super::ColumnRef), - - ParamRef(super::ParamRef), - - AConst(Box<super::AConst>), - - FuncCall(Box<super::FuncCall>), - - AStar(super::AStar), - - AIndices(Box<super::AIndices>), - - AIndirection(Box<super::AIndirection>), - - AArrayExpr(super::AArrayExpr), - - ResTarget(Box<super::ResTarget>), - - MultiAssignRef(Box<super::MultiAssignRef>), - - TypeCast(Box<super::TypeCast>), - - CollateClause(Box<super::CollateClause>), - - SortBy(Box<super::SortBy>), - - WindowDef(Box<super::WindowDef>), - - RangeSubselect(Box<super::RangeSubselect>), - - RangeFunction(super::RangeFunction), - - RangeTableSample(Box<super::RangeTableSample>), - - RangeTableFunc(Box<super::RangeTableFunc>), - - RangeTableFuncCol(Box<super::RangeTableFuncCol>), - - TypeName(super::TypeName), - - ColumnDef(Box<super::ColumnDef>), - - IndexElem(Box<super::IndexElem>), - - Constraint(Box<super::Constraint>), - - DefElem(Box<super::DefElem>), - - RangeTblEntry(Box<super::RangeTblEntry>), - - RangeTblFunction(Box<super::RangeTblFunction>), - - TableSampleClause(Box<super::TableSampleClause>), - - WithCheckOption(Box<super::WithCheckOption>), - - SortGroupClause(super::SortGroupClause), - - GroupingSet(super::GroupingSet), - - WindowClause(Box<super::WindowClause>), - - ObjectWithArgs(super::ObjectWithArgs), - - AccessPriv(super::AccessPriv), - - CreateOpClassItem(super::CreateOpClassItem), - - TableLikeClause(super::TableLikeClause), - - FunctionParameter(Box<super::FunctionParameter>), - - LockingClause(super::LockingClause), - - RowMarkClause(super::RowMarkClause), - - XmlSerialize(Box<super::XmlSerialize>), - - WithClause(super::WithClause), - - InferClause(Box<super::InferClause>), - - OnConflictClause(Box<super::OnConflictClause>), - - CommonTableExpr(Box<super::CommonTableExpr>), - - RoleSpec(super::RoleSpec), - - TriggerTransition(super::TriggerTransition), - - PartitionElem(Box<super::PartitionElem>), - - PartitionSpec(super::PartitionSpec), - - PartitionBoundSpec(super::PartitionBoundSpec), - - PartitionRangeDatum(Box<super::PartitionRangeDatum>), - - PartitionCmd(super::PartitionCmd), - - VacuumRelation(super::VacuumRelation), - - InlineCodeBlock(super::InlineCodeBlock), - - CallContext(super::CallContext), - - Integer(super::Integer), - - Float(super::Float), - - String(super::String2), - - BitString(super::BitString), - - Null(super::Null), - - List(super::List), - - IntList(super::IntList), - - OidList(super::OidList), - } -} -#[derive(Clone, PartialEq)] -pub struct Integer { - /// machine integer - - pub ival: i32, -} -#[derive(Clone, PartialEq)] -pub struct Float { - /// string - - pub str: String, -} -#[derive(Clone, PartialEq)] -pub struct String2 { - /// string - - pub str: String, -} -#[derive(Clone, PartialEq)] -pub struct BitString { - /// string - - pub str: String, -} -/// intentionally empty -#[derive(Clone, PartialEq)] -pub struct Null {} -#[derive(Clone, PartialEq)] -pub struct List { - - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct OidList { - - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct IntList { - - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct Alias { - - pub aliasname: String, - - pub colnames: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RangeVar { - - pub catalogname: String, - - pub schemaname: String, - - pub relname: String, - - pub inh: bool, - - pub relpersistence: String, - - pub alias: ::core::option::Option<Alias>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct TableFunc { - - pub ns_uris: Vec<Node>, - - pub ns_names: Vec<Node>, - - pub docexpr: ::core::option::Option<Box<Node>>, - - pub rowexpr: ::core::option::Option<Box<Node>>, - - pub colnames: Vec<Node>, - - pub coltypes: Vec<Node>, - - pub coltypmods: Vec<Node>, - - pub colcollations: Vec<Node>, - - pub colexprs: Vec<Node>, - - pub coldefexprs: Vec<Node>, - - pub notnulls: Vec<u64>, - - pub ordinalitycol: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct Expr {} -#[derive(Clone, PartialEq)] -pub struct Var { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub varno: u32, - - pub varattno: i32, - - pub vartype: u32, - - pub vartypmod: i32, - - pub varcollid: u32, - - pub varlevelsup: u32, - - pub varnosyn: u32, - - pub varattnosyn: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct Param { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub paramkind: i32, - - pub paramid: i32, - - pub paramtype: u32, - - pub paramtypmod: i32, - - pub paramcollid: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct Aggref { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub aggfnoid: u32, - - pub aggtype: u32, - - pub aggcollid: u32, - - pub inputcollid: u32, - - pub aggtranstype: u32, - - pub aggargtypes: Vec<Node>, - - pub aggdirectargs: Vec<Node>, - - pub args: Vec<Node>, - - pub aggorder: Vec<Node>, - - pub aggdistinct: Vec<Node>, - - pub aggfilter: ::core::option::Option<Box<Node>>, - - pub aggstar: bool, - - pub aggvariadic: bool, - - pub aggkind: String, - - pub agglevelsup: u32, - - pub aggsplit: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct GroupingFunc { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub args: Vec<Node>, - - pub refs: Vec<Node>, - - pub cols: Vec<Node>, - - pub agglevelsup: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WindowFunc { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub winfnoid: u32, - - pub wintype: u32, - - pub wincollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub aggfilter: ::core::option::Option<Box<Node>>, - - pub winref: u32, - - pub winstar: bool, - - pub winagg: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SubscriptingRef { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub refcontainertype: u32, - - pub refelemtype: u32, - - pub reftypmod: i32, - - pub refcollid: u32, - - pub refupperindexpr: Vec<Node>, - - pub reflowerindexpr: Vec<Node>, - - pub refexpr: ::core::option::Option<Box<Node>>, - - pub refassgnexpr: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct FuncExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub funcid: u32, - - pub funcresulttype: u32, - - pub funcretset: bool, - - pub funcvariadic: bool, - - pub funcformat: i32, - - pub funccollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct NamedArgExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub name: String, - - pub argnumber: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct OpExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub opresulttype: u32, - - pub opretset: bool, - - pub opcollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct DistinctExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub opresulttype: u32, - - pub opretset: bool, - - pub opcollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct NullIfExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub opresulttype: u32, - - pub opretset: bool, - - pub opcollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ScalarArrayOpExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub use_or: bool, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct BoolExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub boolop: i32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SubLink { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub sub_link_type: i32, - - pub sub_link_id: i32, - - pub testexpr: ::core::option::Option<Box<Node>>, - - pub oper_name: Vec<Node>, - - pub subselect: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SubPlan { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub sub_link_type: i32, - - pub testexpr: ::core::option::Option<Box<Node>>, - - pub param_ids: Vec<Node>, - - pub plan_id: i32, - - pub plan_name: String, - - pub first_col_type: u32, - - pub first_col_typmod: i32, - - pub first_col_collation: u32, - - pub use_hash_table: bool, - - pub unknown_eq_false: bool, - - pub parallel_safe: bool, - - pub set_param: Vec<Node>, - - pub par_param: Vec<Node>, - - pub args: Vec<Node>, - - pub startup_cost: f64, - - pub per_call_cost: f64, -} -#[derive(Clone, PartialEq)] -pub struct AlternativeSubPlan { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub subplans: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct FieldSelect { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub fieldnum: i32, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, -} -#[derive(Clone, PartialEq)] -pub struct FieldStore { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub newvals: Vec<Node>, - - pub fieldnums: Vec<Node>, - - pub resulttype: u32, -} -#[derive(Clone, PartialEq)] -pub struct RelabelType { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, - - pub relabelformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CoerceViaIo { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resultcollid: u32, - - pub coerceformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ArrayCoerceExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub elemexpr: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, - - pub coerceformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ConvertRowtypeExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub convertformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CollateExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub coll_oid: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CaseExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub casetype: u32, - - pub casecollid: u32, - - pub arg: ::core::option::Option<Box<Node>>, - - pub args: Vec<Node>, - - pub defresult: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CaseWhen { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub expr: ::core::option::Option<Box<Node>>, - - pub result: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CaseTestExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub type_id: u32, - - pub type_mod: i32, - - pub collation: u32, -} -#[derive(Clone, PartialEq)] -pub struct ArrayExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub array_typeid: u32, - - pub array_collid: u32, - - pub element_typeid: u32, - - pub elements: Vec<Node>, - - pub multidims: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RowExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub args: Vec<Node>, - - pub row_typeid: u32, - - pub row_format: i32, - - pub colnames: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RowCompareExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub rctype: i32, - - pub opnos: Vec<Node>, - - pub opfamilies: Vec<Node>, - - pub inputcollids: Vec<Node>, - - pub largs: Vec<Node>, - - pub rargs: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CoalesceExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub coalescetype: u32, - - pub coalescecollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct MinMaxExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub minmaxtype: u32, - - pub minmaxcollid: u32, - - pub inputcollid: u32, - - pub op: i32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SqlValueFunction { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub op: i32, - - pub r#type: u32, - - pub typmod: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct XmlExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub op: i32, - - pub name: String, - - pub named_args: Vec<Node>, - - pub arg_names: Vec<Node>, - - pub args: Vec<Node>, - - pub xmloption: i32, - - pub r#type: u32, - - pub typmod: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct NullTest { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub nulltesttype: i32, - - pub argisrow: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct BooleanTest { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub booltesttype: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CoerceToDomain { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, - - pub coercionformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CoerceToDomainValue { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub type_id: u32, - - pub type_mod: i32, - - pub collation: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SetToDefault { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub type_id: u32, - - pub type_mod: i32, - - pub collation: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CurrentOfExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub cvarno: u32, - - pub cursor_name: String, - - pub cursor_param: i32, -} -#[derive(Clone, PartialEq)] -pub struct NextValueExpr { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub seqid: u32, - - pub type_id: u32, -} -#[derive(Clone, PartialEq)] -pub struct InferenceElem { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub expr: ::core::option::Option<Box<Node>>, - - pub infercollid: u32, - - pub inferopclass: u32, -} -#[derive(Clone, PartialEq)] -pub struct TargetEntry { - - pub xpr: ::core::option::Option<Box<Node>>, - - pub expr: ::core::option::Option<Box<Node>>, - - pub resno: i32, - - pub resname: String, - - pub ressortgroupref: u32, - - pub resorigtbl: u32, - - pub resorigcol: i32, - - pub resjunk: bool, -} -#[derive(Clone, PartialEq)] -pub struct RangeTblRef { - - pub rtindex: i32, -} -#[derive(Clone, PartialEq)] -pub struct JoinExpr { - - pub jointype: i32, - - pub is_natural: bool, - - pub larg: ::core::option::Option<Box<Node>>, - - pub rarg: ::core::option::Option<Box<Node>>, - - pub using_clause: Vec<Node>, - - pub quals: ::core::option::Option<Box<Node>>, - - pub alias: ::core::option::Option<Alias>, - - pub rtindex: i32, -} -#[derive(Clone, PartialEq)] -pub struct FromExpr { - - pub fromlist: Vec<Node>, - - pub quals: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct OnConflictExpr { - - pub action: i32, - - pub arbiter_elems: Vec<Node>, - - pub arbiter_where: ::core::option::Option<Box<Node>>, - - pub constraint: u32, - - pub on_conflict_set: Vec<Node>, - - pub on_conflict_where: ::core::option::Option<Box<Node>>, - - pub excl_rel_index: i32, - - pub excl_rel_tlist: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct IntoClause { - - pub rel: ::core::option::Option<RangeVar>, - - pub col_names: Vec<Node>, - - pub access_method: String, - - pub options: Vec<Node>, - - pub on_commit: i32, - - pub table_space_name: String, - - pub view_query: ::core::option::Option<Box<Node>>, - - pub skip_data: bool, -} -#[derive(Clone, PartialEq)] -pub struct RawStmt { - - pub stmt: ::core::option::Option<Box<Node>>, - - pub stmt_location: i32, - - pub stmt_len: i32, -} -#[derive(Clone, PartialEq)] -pub struct Query { - - pub command_type: i32, - - pub query_source: i32, - - pub can_set_tag: bool, - - pub utility_stmt: ::core::option::Option<Box<Node>>, - - pub result_relation: i32, - - pub has_aggs: bool, - - pub has_window_funcs: bool, - - pub has_target_srfs: bool, - - pub has_sub_links: bool, - - pub has_distinct_on: bool, - - pub has_recursive: bool, - - pub has_modifying_cte: bool, - - pub has_for_update: bool, - - pub has_row_security: bool, - - pub cte_list: Vec<Node>, - - pub rtable: Vec<Node>, - - pub jointree: ::core::option::Option<Box<FromExpr>>, - - pub target_list: Vec<Node>, - - pub r#override: i32, - - pub on_conflict: ::core::option::Option<Box<OnConflictExpr>>, - - pub returning_list: Vec<Node>, - - pub group_clause: Vec<Node>, - - pub grouping_sets: Vec<Node>, - - pub having_qual: ::core::option::Option<Box<Node>>, - - pub window_clause: Vec<Node>, - - pub distinct_clause: Vec<Node>, - - pub sort_clause: Vec<Node>, - - pub limit_offset: ::core::option::Option<Box<Node>>, - - pub limit_count: ::core::option::Option<Box<Node>>, - - pub limit_option: i32, - - pub row_marks: Vec<Node>, - - pub set_operations: ::core::option::Option<Box<Node>>, - - pub constraint_deps: Vec<Node>, - - pub with_check_options: Vec<Node>, - - pub stmt_location: i32, - - pub stmt_len: i32, -} -#[derive(Clone, PartialEq)] -pub struct InsertStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub cols: Vec<Node>, - - pub select_stmt: ::core::option::Option<Box<Node>>, - - pub on_conflict_clause: ::core::option::Option<Box<OnConflictClause>>, - - pub returning_list: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, - - pub r#override: i32, -} -#[derive(Clone, PartialEq)] -pub struct DeleteStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub using_clause: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub returning_list: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, -} -#[derive(Clone, PartialEq)] -pub struct UpdateStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub target_list: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub from_clause: Vec<Node>, - - pub returning_list: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, -} -#[derive(Clone, PartialEq)] -pub struct SelectStmt { - - pub distinct_clause: Vec<Node>, - - pub into_clause: ::core::option::Option<Box<IntoClause>>, - - pub target_list: Vec<Node>, - - pub from_clause: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub group_clause: Vec<Node>, - - pub having_clause: ::core::option::Option<Box<Node>>, - - pub window_clause: Vec<Node>, - - pub values_lists: Vec<Node>, - - pub sort_clause: Vec<Node>, - - pub limit_offset: ::core::option::Option<Box<Node>>, - - pub limit_count: ::core::option::Option<Box<Node>>, - - pub limit_option: i32, - - pub locking_clause: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, - - pub op: i32, - - pub all: bool, - - pub larg: ::core::option::Option<Box<SelectStmt>>, - - pub rarg: ::core::option::Option<Box<SelectStmt>>, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub cmds: Vec<Node>, - - pub relkind: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableCmd { - - pub subtype: i32, - - pub name: String, - - pub num: i32, - - pub newowner: ::core::option::Option<RoleSpec>, - - pub def: ::core::option::Option<Box<Node>>, - - pub behavior: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterDomainStmt { - - pub subtype: String, - - pub type_name: Vec<Node>, - - pub name: String, - - pub def: ::core::option::Option<Box<Node>>, - - pub behavior: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct SetOperationStmt { - - pub op: i32, - - pub all: bool, - - pub larg: ::core::option::Option<Box<Node>>, - - pub rarg: ::core::option::Option<Box<Node>>, - - pub col_types: Vec<Node>, - - pub col_typmods: Vec<Node>, - - pub col_collations: Vec<Node>, - - pub group_clauses: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct GrantStmt { - - pub is_grant: bool, - - pub targtype: i32, - - pub objtype: i32, - - pub objects: Vec<Node>, - - pub privileges: Vec<Node>, - - pub grantees: Vec<Node>, - - pub grant_option: bool, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct GrantRoleStmt { - - pub granted_roles: Vec<Node>, - - pub grantee_roles: Vec<Node>, - - pub is_grant: bool, - - pub admin_opt: bool, - - pub grantor: ::core::option::Option<RoleSpec>, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct AlterDefaultPrivilegesStmt { - - pub options: Vec<Node>, - - pub action: ::core::option::Option<GrantStmt>, -} -#[derive(Clone, PartialEq)] -pub struct ClosePortalStmt { - - pub portalname: String, -} -#[derive(Clone, PartialEq)] -pub struct ClusterStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub indexname: String, - - pub options: i32, -} -#[derive(Clone, PartialEq)] -pub struct CopyStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub query: ::core::option::Option<Box<Node>>, - - pub attlist: Vec<Node>, - - pub is_from: bool, - - pub is_program: bool, - - pub filename: String, - - pub options: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub table_elts: Vec<Node>, - - pub inh_relations: Vec<Node>, - - pub partbound: ::core::option::Option<PartitionBoundSpec>, - - pub partspec: ::core::option::Option<PartitionSpec>, - - pub of_typename: ::core::option::Option<TypeName>, - - pub constraints: Vec<Node>, - - pub options: Vec<Node>, - - pub oncommit: i32, - - pub tablespacename: String, - - pub access_method: String, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct DefineStmt { - - pub kind: i32, - - pub oldstyle: bool, - - pub defnames: Vec<Node>, - - pub args: Vec<Node>, - - pub definition: Vec<Node>, - - pub if_not_exists: bool, - - pub replace: bool, -} -#[derive(Clone, PartialEq)] -pub struct DropStmt { - - pub objects: Vec<Node>, - - pub remove_type: i32, - - pub behavior: i32, - - pub missing_ok: bool, - - pub concurrent: bool, -} -#[derive(Clone, PartialEq)] -pub struct TruncateStmt { - - pub relations: Vec<Node>, - - pub restart_seqs: bool, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct CommentStmt { - - pub objtype: i32, - - pub object: ::core::option::Option<Box<Node>>, - - pub comment: String, -} -#[derive(Clone, PartialEq)] -pub struct FetchStmt { - - pub direction: i32, - - pub how_many: i64, - - pub portalname: String, - - pub ismove: bool, -} -#[derive(Clone, PartialEq)] -pub struct IndexStmt { - - pub idxname: String, - - pub relation: ::core::option::Option<RangeVar>, - - pub access_method: String, - - pub table_space: String, - - pub index_params: Vec<Node>, - - pub index_including_params: Vec<Node>, - - pub options: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub exclude_op_names: Vec<Node>, - - pub idxcomment: String, - - pub index_oid: u32, - - pub old_node: u32, - - pub old_create_subid: u32, - - pub old_first_relfilenode_subid: u32, - - pub unique: bool, - - pub primary: bool, - - pub isconstraint: bool, - - pub deferrable: bool, - - pub initdeferred: bool, - - pub transformed: bool, - - pub concurrent: bool, - - pub if_not_exists: bool, - - pub reset_default_tblspc: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateFunctionStmt { - - pub is_procedure: bool, - - pub replace: bool, - - pub funcname: Vec<Node>, - - pub parameters: Vec<Node>, - - pub return_type: ::core::option::Option<TypeName>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterFunctionStmt { - - pub objtype: i32, - - pub func: ::core::option::Option<ObjectWithArgs>, - - pub actions: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DoStmt { - - pub args: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RenameStmt { - - pub rename_type: i32, - - pub relation_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub subname: String, - - pub newname: String, - - pub behavior: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct RuleStmt { - - pub relation: ::core::option::Option<RangeVar>, - - pub rulename: String, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub event: i32, - - pub instead: bool, - - pub actions: Vec<Node>, - - pub replace: bool, -} -#[derive(Clone, PartialEq)] -pub struct NotifyStmt { - - pub conditionname: String, - - pub payload: String, -} -#[derive(Clone, PartialEq)] -pub struct ListenStmt { - - pub conditionname: String, -} -#[derive(Clone, PartialEq)] -pub struct UnlistenStmt { - - pub conditionname: String, -} -#[derive(Clone, PartialEq)] -pub struct TransactionStmt { - - pub kind: i32, - - pub options: Vec<Node>, - - pub savepoint_name: String, - - pub gid: String, - - pub chain: bool, -} -#[derive(Clone, PartialEq)] -pub struct ViewStmt { - - pub view: ::core::option::Option<RangeVar>, - - pub aliases: Vec<Node>, - - pub query: ::core::option::Option<Box<Node>>, - - pub replace: bool, - - pub options: Vec<Node>, - - pub with_check_option: i32, -} -#[derive(Clone, PartialEq)] -pub struct LoadStmt { - - pub filename: String, -} -#[derive(Clone, PartialEq)] -pub struct CreateDomainStmt { - - pub domainname: Vec<Node>, - - pub type_name: ::core::option::Option<TypeName>, - - pub coll_clause: ::core::option::Option<Box<CollateClause>>, - - pub constraints: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreatedbStmt { - - pub dbname: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropdbStmt { - - pub dbname: String, - - pub missing_ok: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct VacuumStmt { - - pub options: Vec<Node>, - - pub rels: Vec<Node>, - - pub is_vacuumcmd: bool, -} -#[derive(Clone, PartialEq)] -pub struct ExplainStmt { - - pub query: ::core::option::Option<Box<Node>>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateTableAsStmt { - - pub query: ::core::option::Option<Box<Node>>, - - pub into: ::core::option::Option<Box<IntoClause>>, - - pub relkind: i32, - - pub is_select_into: bool, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateSeqStmt { - - pub sequence: ::core::option::Option<RangeVar>, - - pub options: Vec<Node>, - - pub owner_id: u32, - - pub for_identity: bool, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterSeqStmt { - - pub sequence: ::core::option::Option<RangeVar>, - - pub options: Vec<Node>, - - pub for_identity: bool, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct VariableSetStmt { - - pub kind: i32, - - pub name: String, - - pub args: Vec<Node>, - - pub is_local: bool, -} -#[derive(Clone, PartialEq)] -pub struct VariableShowStmt { - - pub name: String, -} -#[derive(Clone, PartialEq)] -pub struct DiscardStmt { - - pub target: i32, -} -#[derive(Clone, PartialEq)] -pub struct CreateTrigStmt { - - pub trigname: String, - - pub relation: ::core::option::Option<RangeVar>, - - pub funcname: Vec<Node>, - - pub args: Vec<Node>, - - pub row: bool, - - pub timing: i32, - - pub events: i32, - - pub columns: Vec<Node>, - - pub when_clause: ::core::option::Option<Box<Node>>, - - pub isconstraint: bool, - - pub transition_rels: Vec<Node>, - - pub deferrable: bool, - - pub initdeferred: bool, - - pub constrrel: ::core::option::Option<RangeVar>, -} -#[derive(Clone, PartialEq)] -pub struct CreatePLangStmt { - - pub replace: bool, - - pub plname: String, - - pub plhandler: Vec<Node>, - - pub plinline: Vec<Node>, - - pub plvalidator: Vec<Node>, - - pub pltrusted: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateRoleStmt { - - pub stmt_type: i32, - - pub role: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterRoleStmt { - - pub role: ::core::option::Option<RoleSpec>, - - pub options: Vec<Node>, - - pub action: i32, -} -#[derive(Clone, PartialEq)] -pub struct DropRoleStmt { - - pub roles: Vec<Node>, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct LockStmt { - - pub relations: Vec<Node>, - - pub mode: i32, - - pub nowait: bool, -} -#[derive(Clone, PartialEq)] -pub struct ConstraintsSetStmt { - - pub constraints: Vec<Node>, - - pub deferred: bool, -} -#[derive(Clone, PartialEq)] -pub struct ReindexStmt { - - pub kind: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub name: String, - - pub options: i32, - - pub concurrent: bool, -} -#[derive(Clone, PartialEq)] -pub struct CheckPointStmt {} -#[derive(Clone, PartialEq)] -pub struct CreateSchemaStmt { - - pub schemaname: String, - - pub authrole: ::core::option::Option<RoleSpec>, - - pub schema_elts: Vec<Node>, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterDatabaseStmt { - - pub dbname: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterDatabaseSetStmt { - - pub dbname: String, - - pub setstmt: ::core::option::Option<VariableSetStmt>, -} -#[derive(Clone, PartialEq)] -pub struct AlterRoleSetStmt { - - pub role: ::core::option::Option<RoleSpec>, - - pub database: String, - - pub setstmt: ::core::option::Option<VariableSetStmt>, -} -#[derive(Clone, PartialEq)] -pub struct CreateConversionStmt { - - pub conversion_name: Vec<Node>, - - pub for_encoding_name: String, - - pub to_encoding_name: String, - - pub func_name: Vec<Node>, - - pub def: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateCastStmt { - - pub sourcetype: ::core::option::Option<TypeName>, - - pub targettype: ::core::option::Option<TypeName>, - - pub func: ::core::option::Option<ObjectWithArgs>, - - pub context: i32, - - pub inout: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateOpClassStmt { - - pub opclassname: Vec<Node>, - - pub opfamilyname: Vec<Node>, - - pub amname: String, - - pub datatype: ::core::option::Option<TypeName>, - - pub items: Vec<Node>, - - pub is_default: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateOpFamilyStmt { - - pub opfamilyname: Vec<Node>, - - pub amname: String, -} -#[derive(Clone, PartialEq)] -pub struct AlterOpFamilyStmt { - - pub opfamilyname: Vec<Node>, - - pub amname: String, - - pub is_drop: bool, - - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct PrepareStmt { - - pub name: String, - - pub argtypes: Vec<Node>, - - pub query: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct ExecuteStmt { - - pub name: String, - - pub params: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DeallocateStmt { - - pub name: String, -} -#[derive(Clone, PartialEq)] -pub struct DeclareCursorStmt { - - pub portalname: String, - - pub options: i32, - - pub query: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateTableSpaceStmt { - - pub tablespacename: String, - - pub owner: ::core::option::Option<RoleSpec>, - - pub location: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropTableSpaceStmt { - - pub tablespacename: String, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterObjectDependsStmt { - - pub object_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub extname: ::core::option::Option<Box<Node>>, - - pub remove: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterObjectSchemaStmt { - - pub object_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub newschema: String, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterOwnerStmt { - - pub object_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub newowner: ::core::option::Option<RoleSpec>, -} -#[derive(Clone, PartialEq)] -pub struct AlterOperatorStmt { - - pub opername: ::core::option::Option<ObjectWithArgs>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterTypeStmt { - - pub type_name: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropOwnedStmt { - - pub roles: Vec<Node>, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct ReassignOwnedStmt { - - pub roles: Vec<Node>, - - pub newrole: ::core::option::Option<RoleSpec>, -} -#[derive(Clone, PartialEq)] -pub struct CompositeTypeStmt { - - pub typevar: ::core::option::Option<RangeVar>, - - pub coldeflist: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateEnumStmt { - - pub type_name: Vec<Node>, - - pub vals: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateRangeStmt { - - pub type_name: Vec<Node>, - - pub params: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterEnumStmt { - - pub type_name: Vec<Node>, - - pub old_val: String, - - pub new_val: String, - - pub new_val_neighbor: String, - - pub new_val_is_after: bool, - - pub skip_if_new_val_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTsDictionaryStmt { - - pub dictname: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterTsConfigurationStmt { - - pub kind: i32, - - pub cfgname: Vec<Node>, - - pub tokentype: Vec<Node>, - - pub dicts: Vec<Node>, - - pub r#override: bool, - - pub replace: bool, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateFdwStmt { - - pub fdwname: String, - - pub func_options: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterFdwStmt { - - pub fdwname: String, - - pub func_options: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateForeignServerStmt { - - pub servername: String, - - pub servertype: String, - - pub version: String, - - pub fdwname: String, - - pub if_not_exists: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterForeignServerStmt { - - pub servername: String, - - pub version: String, - - pub options: Vec<Node>, - - pub has_version: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateUserMappingStmt { - - pub user: ::core::option::Option<RoleSpec>, - - pub servername: String, - - pub if_not_exists: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterUserMappingStmt { - - pub user: ::core::option::Option<RoleSpec>, - - pub servername: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropUserMappingStmt { - - pub user: ::core::option::Option<RoleSpec>, - - pub servername: String, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableSpaceOptionsStmt { - - pub tablespacename: String, - - pub options: Vec<Node>, - - pub is_reset: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableMoveAllStmt { - - pub orig_tablespacename: String, - - pub objtype: i32, - - pub roles: Vec<Node>, - - pub new_tablespacename: String, - - pub nowait: bool, -} -#[derive(Clone, PartialEq)] -pub struct SecLabelStmt { - - pub objtype: i32, - - pub object: ::core::option::Option<Box<Node>>, - - pub provider: String, - - pub label: String, -} -#[derive(Clone, PartialEq)] -pub struct CreateForeignTableStmt { - - pub base_stmt: ::core::option::Option<CreateStmt>, - - pub servername: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct ImportForeignSchemaStmt { - - pub server_name: String, - - pub remote_schema: String, - - pub local_schema: String, - - pub list_type: i32, - - pub table_list: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateExtensionStmt { - - pub extname: String, - - pub if_not_exists: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterExtensionStmt { - - pub extname: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterExtensionContentsStmt { - - pub extname: String, - - pub action: i32, - - pub objtype: i32, - - pub object: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateEventTrigStmt { - - pub trigname: String, - - pub eventname: String, - - pub whenclause: Vec<Node>, - - pub funcname: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterEventTrigStmt { - - pub trigname: String, - - pub tgenabled: String, -} -#[derive(Clone, PartialEq)] -pub struct RefreshMatViewStmt { - - pub concurrent: bool, - - pub skip_data: bool, - - pub relation: ::core::option::Option<RangeVar>, -} -#[derive(Clone, PartialEq)] -pub struct ReplicaIdentityStmt { - - pub identity_type: String, - - pub name: String, -} -#[derive(Clone, PartialEq)] -pub struct AlterSystemStmt { - - pub setstmt: ::core::option::Option<VariableSetStmt>, -} -#[derive(Clone, PartialEq)] -pub struct CreatePolicyStmt { - - pub policy_name: String, - - pub table: ::core::option::Option<RangeVar>, - - pub cmd_name: String, - - pub permissive: bool, - - pub roles: Vec<Node>, - - pub qual: ::core::option::Option<Box<Node>>, - - pub with_check: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct AlterPolicyStmt { - - pub policy_name: String, - - pub table: ::core::option::Option<RangeVar>, - - pub roles: Vec<Node>, - - pub qual: ::core::option::Option<Box<Node>>, - - pub with_check: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateTransformStmt { - - pub replace: bool, - - pub type_name: ::core::option::Option<TypeName>, - - pub lang: String, - - pub fromsql: ::core::option::Option<ObjectWithArgs>, - - pub tosql: ::core::option::Option<ObjectWithArgs>, -} -#[derive(Clone, PartialEq)] -pub struct CreateAmStmt { - - pub amname: String, - - pub handler_name: Vec<Node>, - - pub amtype: String, -} -#[derive(Clone, PartialEq)] -pub struct CreatePublicationStmt { - - pub pubname: String, - - pub options: Vec<Node>, - - pub tables: Vec<Node>, - - pub for_all_tables: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterPublicationStmt { - - pub pubname: String, - - pub options: Vec<Node>, - - pub tables: Vec<Node>, - - pub for_all_tables: bool, - - pub table_action: i32, -} -#[derive(Clone, PartialEq)] -pub struct CreateSubscriptionStmt { - - pub subname: String, - - pub conninfo: String, - - pub publication: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterSubscriptionStmt { - - pub kind: i32, - - pub subname: String, - - pub conninfo: String, - - pub publication: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropSubscriptionStmt { - - pub subname: String, - - pub missing_ok: bool, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct CreateStatsStmt { - - pub defnames: Vec<Node>, - - pub stat_types: Vec<Node>, - - pub exprs: Vec<Node>, - - pub relations: Vec<Node>, - - pub stxcomment: String, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterCollationStmt { - - pub collname: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CallStmt { - - pub funccall: ::core::option::Option<Box<FuncCall>>, - - pub funcexpr: ::core::option::Option<Box<FuncExpr>>, -} -#[derive(Clone, PartialEq)] -pub struct AlterStatsStmt { - - pub defnames: Vec<Node>, - - pub stxstattarget: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AExpr { - - pub kind: i32, - - pub name: Vec<Node>, - - pub lexpr: ::core::option::Option<Box<Node>>, - - pub rexpr: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ColumnRef { - - pub fields: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ParamRef { - - pub number: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct AConst { - - pub val: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct FuncCall { - - pub funcname: Vec<Node>, - - pub args: Vec<Node>, - - pub agg_order: Vec<Node>, - - pub agg_filter: ::core::option::Option<Box<Node>>, - - pub agg_within_group: bool, - - pub agg_star: bool, - - pub agg_distinct: bool, - - pub func_variadic: bool, - - pub over: ::core::option::Option<Box<WindowDef>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct AStar {} -#[derive(Clone, PartialEq)] -pub struct AIndices { - - pub is_slice: bool, - - pub lidx: ::core::option::Option<Box<Node>>, - - pub uidx: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct AIndirection { - - pub arg: ::core::option::Option<Box<Node>>, - - pub indirection: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AArrayExpr { - - pub elements: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ResTarget { - - pub name: String, - - pub indirection: Vec<Node>, - - pub val: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct MultiAssignRef { - - pub source: ::core::option::Option<Box<Node>>, - - pub colno: i32, - - pub ncolumns: i32, -} -#[derive(Clone, PartialEq)] -pub struct TypeCast { - - pub arg: ::core::option::Option<Box<Node>>, - - pub type_name: ::core::option::Option<TypeName>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CollateClause { - - pub arg: ::core::option::Option<Box<Node>>, - - pub collname: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SortBy { - - pub node: ::core::option::Option<Box<Node>>, - - pub sortby_dir: i32, - - pub sortby_nulls: i32, - - pub use_op: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WindowDef { - - pub name: String, - - pub refname: String, - - pub partition_clause: Vec<Node>, - - pub order_clause: Vec<Node>, - - pub frame_options: i32, - - pub start_offset: ::core::option::Option<Box<Node>>, - - pub end_offset: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeSubselect { - - pub lateral: bool, - - pub subquery: ::core::option::Option<Box<Node>>, - - pub alias: ::core::option::Option<Alias>, -} -#[derive(Clone, PartialEq)] -pub struct RangeFunction { - - pub lateral: bool, - - pub ordinality: bool, - - pub is_rowsfrom: bool, - - pub functions: Vec<Node>, - - pub alias: ::core::option::Option<Alias>, - - pub coldeflist: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RangeTableSample { - - pub relation: ::core::option::Option<Box<Node>>, - - pub method: Vec<Node>, - - pub args: Vec<Node>, - - pub repeatable: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeTableFunc { - - pub lateral: bool, - - pub docexpr: ::core::option::Option<Box<Node>>, - - pub rowexpr: ::core::option::Option<Box<Node>>, - - pub namespaces: Vec<Node>, - - pub columns: Vec<Node>, - - pub alias: ::core::option::Option<Alias>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeTableFuncCol { - - pub colname: String, - - pub type_name: ::core::option::Option<TypeName>, - - pub for_ordinality: bool, - - pub is_not_null: bool, - - pub colexpr: ::core::option::Option<Box<Node>>, - - pub coldefexpr: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct TypeName { - - pub names: Vec<Node>, - - pub type_oid: u32, - - pub setof: bool, - - pub pct_type: bool, - - pub typmods: Vec<Node>, - - pub typemod: i32, - - pub array_bounds: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ColumnDef { - - pub colname: String, - - pub type_name: ::core::option::Option<TypeName>, - - pub inhcount: i32, - - pub is_local: bool, - - pub is_not_null: bool, - - pub is_from_type: bool, - - pub storage: String, - - pub raw_default: ::core::option::Option<Box<Node>>, - - pub cooked_default: ::core::option::Option<Box<Node>>, - - pub identity: String, - - pub identity_sequence: ::core::option::Option<RangeVar>, - - pub generated: String, - - pub coll_clause: ::core::option::Option<Box<CollateClause>>, - - pub coll_oid: u32, - - pub constraints: Vec<Node>, - - pub fdwoptions: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct IndexElem { - - pub name: String, - - pub expr: ::core::option::Option<Box<Node>>, - - pub indexcolname: String, - - pub collation: Vec<Node>, - - pub opclass: Vec<Node>, - - pub opclassopts: Vec<Node>, - - pub ordering: i32, - - pub nulls_ordering: i32, -} -#[derive(Clone, PartialEq)] -pub struct Constraint { - - pub contype: i32, - - pub conname: String, - - pub deferrable: bool, - - pub initdeferred: bool, - - pub location: i32, - - pub is_no_inherit: bool, - - pub raw_expr: ::core::option::Option<Box<Node>>, - - pub cooked_expr: String, - - pub generated_when: String, - - pub keys: Vec<Node>, - - pub including: Vec<Node>, - - pub exclusions: Vec<Node>, - - pub options: Vec<Node>, - - pub indexname: String, - - pub indexspace: String, - - pub reset_default_tblspc: bool, - - pub access_method: String, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub pktable: ::core::option::Option<RangeVar>, - - pub fk_attrs: Vec<Node>, - - pub pk_attrs: Vec<Node>, - - pub fk_matchtype: String, - - pub fk_upd_action: String, - - pub fk_del_action: String, - - pub old_conpfeqop: Vec<Node>, - - pub old_pktable_oid: u32, - - pub skip_validation: bool, - - pub initially_valid: bool, -} -#[derive(Clone, PartialEq)] -pub struct DefElem { - - pub defnamespace: String, - - pub defname: String, - - pub arg: ::core::option::Option<Box<Node>>, - - pub defaction: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeTblEntry { - - pub rtekind: i32, - - pub relid: u32, - - pub relkind: String, - - pub rellockmode: i32, - - pub tablesample: ::core::option::Option<Box<TableSampleClause>>, - - pub subquery: ::core::option::Option<Box<Query>>, - - pub security_barrier: bool, - - pub jointype: i32, - - pub joinmergedcols: i32, - - pub joinaliasvars: Vec<Node>, - - pub joinleftcols: Vec<Node>, - - pub joinrightcols: Vec<Node>, - - pub functions: Vec<Node>, - - pub funcordinality: bool, - - pub tablefunc: ::core::option::Option<Box<TableFunc>>, - - pub values_lists: Vec<Node>, - - pub ctename: String, - - pub ctelevelsup: u32, - - pub self_reference: bool, - - pub coltypes: Vec<Node>, - - pub coltypmods: Vec<Node>, - - pub colcollations: Vec<Node>, - - pub enrname: String, - - pub enrtuples: f64, - - pub alias: ::core::option::Option<Alias>, - - pub eref: ::core::option::Option<Alias>, - - pub lateral: bool, - - pub inh: bool, - - pub in_from_cl: bool, - - pub required_perms: u32, - - pub check_as_user: u32, - - pub selected_cols: Vec<u64>, - - pub inserted_cols: Vec<u64>, - - pub updated_cols: Vec<u64>, - - pub extra_updated_cols: Vec<u64>, - - pub security_quals: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RangeTblFunction { - - pub funcexpr: ::core::option::Option<Box<Node>>, - - pub funccolcount: i32, - - pub funccolnames: Vec<Node>, - - pub funccoltypes: Vec<Node>, - - pub funccoltypmods: Vec<Node>, - - pub funccolcollations: Vec<Node>, - - pub funcparams: Vec<u64>, -} -#[derive(Clone, PartialEq)] -pub struct TableSampleClause { - - pub tsmhandler: u32, - - pub args: Vec<Node>, - - pub repeatable: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct WithCheckOption { - - pub kind: i32, - - pub relname: String, - - pub polname: String, - - pub qual: ::core::option::Option<Box<Node>>, - - pub cascaded: bool, -} -#[derive(Clone, PartialEq)] -pub struct SortGroupClause { - - pub tle_sort_group_ref: u32, - - pub eqop: u32, - - pub sortop: u32, - - pub nulls_first: bool, - - pub hashable: bool, -} -#[derive(Clone, PartialEq)] -pub struct GroupingSet { - - pub kind: i32, - - pub content: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WindowClause { - - pub name: String, - - pub refname: String, - - pub partition_clause: Vec<Node>, - - pub order_clause: Vec<Node>, - - pub frame_options: i32, - - pub start_offset: ::core::option::Option<Box<Node>>, - - pub end_offset: ::core::option::Option<Box<Node>>, - - pub start_in_range_func: u32, - - pub end_in_range_func: u32, - - pub in_range_coll: u32, - - pub in_range_asc: bool, - - pub in_range_nulls_first: bool, - - pub winref: u32, - - pub copied_order: bool, -} -#[derive(Clone, PartialEq)] -pub struct ObjectWithArgs { - - pub objname: Vec<Node>, - - pub objargs: Vec<Node>, - - pub args_unspecified: bool, -} -#[derive(Clone, PartialEq)] -pub struct AccessPriv { - - pub priv_name: String, - - pub cols: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateOpClassItem { - - pub itemtype: i32, - - pub name: ::core::option::Option<ObjectWithArgs>, - - pub number: i32, - - pub order_family: Vec<Node>, - - pub class_args: Vec<Node>, - - pub storedtype: ::core::option::Option<TypeName>, -} -#[derive(Clone, PartialEq)] -pub struct TableLikeClause { - - pub relation: ::core::option::Option<RangeVar>, - - pub options: u32, - - pub relation_oid: u32, -} -#[derive(Clone, PartialEq)] -pub struct FunctionParameter { - - pub name: String, - - pub arg_type: ::core::option::Option<TypeName>, - - pub mode: i32, - - pub defexpr: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct LockingClause { - - pub locked_rels: Vec<Node>, - - pub strength: i32, - - pub wait_policy: i32, -} -#[derive(Clone, PartialEq)] -pub struct RowMarkClause { - - pub rti: u32, - - pub strength: i32, - - pub wait_policy: i32, - - pub pushed_down: bool, -} -#[derive(Clone, PartialEq)] -pub struct XmlSerialize { - - pub xmloption: i32, - - pub expr: ::core::option::Option<Box<Node>>, - - pub type_name: ::core::option::Option<TypeName>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WithClause { - - pub ctes: Vec<Node>, - - pub recursive: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct InferClause { - - pub index_elems: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub conname: String, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct OnConflictClause { - - pub action: i32, - - pub infer: ::core::option::Option<Box<InferClause>>, - - pub target_list: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CommonTableExpr { - - pub ctename: String, - - pub aliascolnames: Vec<Node>, - - pub ctematerialized: i32, - - pub ctequery: ::core::option::Option<Box<Node>>, - - pub location: i32, - - pub cterecursive: bool, - - pub cterefcount: i32, - - pub ctecolnames: Vec<Node>, - - pub ctecoltypes: Vec<Node>, - - pub ctecoltypmods: Vec<Node>, - - pub ctecolcollations: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RoleSpec { - - pub roletype: i32, - - pub rolename: String, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct TriggerTransition { - - pub name: String, - - pub is_new: bool, - - pub is_table: bool, -} -#[derive(Clone, PartialEq)] -pub struct PartitionElem { - - pub name: String, - - pub expr: ::core::option::Option<Box<Node>>, - - pub collation: Vec<Node>, - - pub opclass: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionSpec { - - pub strategy: String, - - pub part_params: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionBoundSpec { - - pub strategy: String, - - pub is_default: bool, - - pub modulus: i32, - - pub remainder: i32, - - pub listdatums: Vec<Node>, - - pub lowerdatums: Vec<Node>, - - pub upperdatums: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionRangeDatum { - - pub kind: i32, - - pub value: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionCmd { - - pub name: ::core::option::Option<RangeVar>, - - pub bound: ::core::option::Option<PartitionBoundSpec>, -} -#[derive(Clone, PartialEq)] -pub struct VacuumRelation { - - pub relation: ::core::option::Option<RangeVar>, - - pub oid: u32, - - pub va_cols: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct InlineCodeBlock { - - pub source_text: String, - - pub lang_oid: u32, - - pub lang_is_trusted: bool, - - pub atomic: bool, -} -#[derive(Clone, PartialEq)] -pub struct CallContext { - - pub atomic: bool, -} -#[derive(Clone, PartialEq)] -pub struct ScanToken { - - pub start: i32, - - pub end: i32, - - pub token: i32, - - pub keyword_kind: i32, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum OverridingKind { - Undefined = 0, - OverridingNotSet = 1, - OverridingUserValue = 2, - OverridingSystemValue = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum QuerySource { - Undefined = 0, - QsrcOriginal = 1, - QsrcParser = 2, - QsrcInsteadRule = 3, - QsrcQualInsteadRule = 4, - QsrcNonInsteadRule = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SortByDir { - Undefined = 0, - SortbyDefault = 1, - SortbyAsc = 2, - SortbyDesc = 3, - SortbyUsing = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SortByNulls { - Undefined = 0, - SortbyNullsDefault = 1, - SortbyNullsFirst = 2, - SortbyNullsLast = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AExprKind { - Undefined = 0, - AexprOp = 1, - AexprOpAny = 2, - AexprOpAll = 3, - AexprDistinct = 4, - AexprNotDistinct = 5, - AexprNullif = 6, - AexprOf = 7, - AexprIn = 8, - AexprLike = 9, - AexprIlike = 10, - AexprSimilar = 11, - AexprBetween = 12, - AexprNotBetween = 13, - AexprBetweenSym = 14, - AexprNotBetweenSym = 15, - AexprParen = 16, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RoleSpecType { - Undefined = 0, - RolespecCstring = 1, - RolespecCurrentUser = 2, - RolespecSessionUser = 3, - RolespecPublic = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum TableLikeOption { - Undefined = 0, - CreateTableLikeComments = 1, - CreateTableLikeConstraints = 2, - CreateTableLikeDefaults = 3, - CreateTableLikeGenerated = 4, - CreateTableLikeIdentity = 5, - CreateTableLikeIndexes = 6, - CreateTableLikeStatistics = 7, - CreateTableLikeStorage = 8, - CreateTableLikeAll = 9, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum DefElemAction { - Undefined = 0, - DefelemUnspec = 1, - DefelemSet = 2, - DefelemAdd = 3, - DefelemDrop = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum PartitionRangeDatumKind { - Undefined = 0, - PartitionRangeDatumMinvalue = 1, - PartitionRangeDatumValue = 2, - PartitionRangeDatumMaxvalue = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RteKind { - RtekindUndefined = 0, - RteRelation = 1, - RteSubquery = 2, - RteJoin = 3, - RteFunction = 4, - RteTablefunc = 5, - RteValues = 6, - RteCte = 7, - RteNamedtuplestore = 8, - RteResult = 9, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum WcoKind { - WcokindUndefined = 0, - WcoViewCheck = 1, - WcoRlsInsertCheck = 2, - WcoRlsUpdateCheck = 3, - WcoRlsConflictCheck = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum GroupingSetKind { - Undefined = 0, - GroupingSetEmpty = 1, - GroupingSetSimple = 2, - GroupingSetRollup = 3, - GroupingSetCube = 4, - GroupingSetSets = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CteMaterialize { - CtematerializeUndefined = 0, - Default = 1, - Always = 2, - Never = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SetOperation { - Undefined = 0, - SetopNone = 1, - SetopUnion = 2, - SetopIntersect = 3, - SetopExcept = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ObjectType { - Undefined = 0, - ObjectAccessMethod = 1, - ObjectAggregate = 2, - ObjectAmop = 3, - ObjectAmproc = 4, - ObjectAttribute = 5, - ObjectCast = 6, - ObjectColumn = 7, - ObjectCollation = 8, - ObjectConversion = 9, - ObjectDatabase = 10, - ObjectDefault = 11, - ObjectDefacl = 12, - ObjectDomain = 13, - ObjectDomconstraint = 14, - ObjectEventTrigger = 15, - ObjectExtension = 16, - ObjectFdw = 17, - ObjectForeignServer = 18, - ObjectForeignTable = 19, - ObjectFunction = 20, - ObjectIndex = 21, - ObjectLanguage = 22, - ObjectLargeobject = 23, - ObjectMatview = 24, - ObjectOpclass = 25, - ObjectOperator = 26, - ObjectOpfamily = 27, - ObjectPolicy = 28, - ObjectProcedure = 29, - ObjectPublication = 30, - ObjectPublicationRel = 31, - ObjectRole = 32, - ObjectRoutine = 33, - ObjectRule = 34, - ObjectSchema = 35, - ObjectSequence = 36, - ObjectSubscription = 37, - ObjectStatisticExt = 38, - ObjectTabconstraint = 39, - ObjectTable = 40, - ObjectTablespace = 41, - ObjectTransform = 42, - ObjectTrigger = 43, - ObjectTsconfiguration = 44, - ObjectTsdictionary = 45, - ObjectTsparser = 46, - ObjectTstemplate = 47, - ObjectType = 48, - ObjectUserMapping = 49, - ObjectView = 50, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum DropBehavior { - Undefined = 0, - DropRestrict = 1, - DropCascade = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AlterTableType { - Undefined = 0, - AtAddColumn = 1, - AtAddColumnRecurse = 2, - AtAddColumnToView = 3, - AtColumnDefault = 4, - AtCookedColumnDefault = 5, - AtDropNotNull = 6, - AtSetNotNull = 7, - AtDropExpression = 8, - AtCheckNotNull = 9, - AtSetStatistics = 10, - AtSetOptions = 11, - AtResetOptions = 12, - AtSetStorage = 13, - AtDropColumn = 14, - AtDropColumnRecurse = 15, - AtAddIndex = 16, - AtReAddIndex = 17, - AtAddConstraint = 18, - AtAddConstraintRecurse = 19, - AtReAddConstraint = 20, - AtReAddDomainConstraint = 21, - AtAlterConstraint = 22, - AtValidateConstraint = 23, - AtValidateConstraintRecurse = 24, - AtAddIndexConstraint = 25, - AtDropConstraint = 26, - AtDropConstraintRecurse = 27, - AtReAddComment = 28, - AtAlterColumnType = 29, - AtAlterColumnGenericOptions = 30, - AtChangeOwner = 31, - AtClusterOn = 32, - AtDropCluster = 33, - AtSetLogged = 34, - AtSetUnLogged = 35, - AtDropOids = 36, - AtSetTableSpace = 37, - AtSetRelOptions = 38, - AtResetRelOptions = 39, - AtReplaceRelOptions = 40, - AtEnableTrig = 41, - AtEnableAlwaysTrig = 42, - AtEnableReplicaTrig = 43, - AtDisableTrig = 44, - AtEnableTrigAll = 45, - AtDisableTrigAll = 46, - AtEnableTrigUser = 47, - AtDisableTrigUser = 48, - AtEnableRule = 49, - AtEnableAlwaysRule = 50, - AtEnableReplicaRule = 51, - AtDisableRule = 52, - AtAddInherit = 53, - AtDropInherit = 54, - AtAddOf = 55, - AtDropOf = 56, - AtReplicaIdentity = 57, - AtEnableRowSecurity = 58, - AtDisableRowSecurity = 59, - AtForceRowSecurity = 60, - AtNoForceRowSecurity = 61, - AtGenericOptions = 62, - AtAttachPartition = 63, - AtDetachPartition = 64, - AtAddIdentity = 65, - AtSetIdentity = 66, - AtDropIdentity = 67, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum GrantTargetType { - Undefined = 0, - AclTargetObject = 1, - AclTargetAllInSchema = 2, - AclTargetDefaults = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum VariableSetKind { - Undefined = 0, - VarSetValue = 1, - VarSetDefault = 2, - VarSetCurrent = 3, - VarSetMulti = 4, - VarReset = 5, - VarResetAll = 6, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ConstrType { - Undefined = 0, - ConstrNull = 1, - ConstrNotnull = 2, - ConstrDefault = 3, - ConstrIdentity = 4, - ConstrGenerated = 5, - ConstrCheck = 6, - ConstrPrimary = 7, - ConstrUnique = 8, - ConstrExclusion = 9, - ConstrForeign = 10, - ConstrAttrDeferrable = 11, - ConstrAttrNotDeferrable = 12, - ConstrAttrDeferred = 13, - ConstrAttrImmediate = 14, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ImportForeignSchemaType { - Undefined = 0, - FdwImportSchemaAll = 1, - FdwImportSchemaLimitTo = 2, - FdwImportSchemaExcept = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RoleStmtType { - Undefined = 0, - RolestmtRole = 1, - RolestmtUser = 2, - RolestmtGroup = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum FetchDirection { - Undefined = 0, - FetchForward = 1, - FetchBackward = 2, - FetchAbsolute = 3, - FetchRelative = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum FunctionParameterMode { - Undefined = 0, - FuncParamIn = 1, - FuncParamOut = 2, - FuncParamInout = 3, - FuncParamVariadic = 4, - FuncParamTable = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum TransactionStmtKind { - Undefined = 0, - TransStmtBegin = 1, - TransStmtStart = 2, - TransStmtCommit = 3, - TransStmtRollback = 4, - TransStmtSavepoint = 5, - TransStmtRelease = 6, - TransStmtRollbackTo = 7, - TransStmtPrepare = 8, - TransStmtCommitPrepared = 9, - TransStmtRollbackPrepared = 10, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ViewCheckOption { - Undefined = 0, - NoCheckOption = 1, - LocalCheckOption = 2, - CascadedCheckOption = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ClusterOption { - Undefined = 0, - CluoptRecheck = 1, - CluoptVerbose = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum DiscardMode { - Undefined = 0, - DiscardAll = 1, - DiscardPlans = 2, - DiscardSequences = 3, - DiscardTemp = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ReindexObjectType { - Undefined = 0, - ReindexObjectIndex = 1, - ReindexObjectTable = 2, - ReindexObjectSchema = 3, - ReindexObjectSystem = 4, - ReindexObjectDatabase = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AlterTsConfigType { - AlterTsconfigTypeUndefined = 0, - AlterTsconfigAddMapping = 1, - AlterTsconfigAlterMappingForToken = 2, - AlterTsconfigReplaceDict = 3, - AlterTsconfigReplaceDictForToken = 4, - AlterTsconfigDropMapping = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AlterSubscriptionType { - Undefined = 0, - AlterSubscriptionOptions = 1, - AlterSubscriptionConnection = 2, - AlterSubscriptionPublication = 3, - AlterSubscriptionRefresh = 4, - AlterSubscriptionEnabled = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum OnCommitAction { - Undefined = 0, - OncommitNoop = 1, - OncommitPreserveRows = 2, - OncommitDeleteRows = 3, - OncommitDrop = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ParamKind { - Undefined = 0, - ParamExtern = 1, - ParamExec = 2, - ParamSublink = 3, - ParamMultiexpr = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CoercionContext { - Undefined = 0, - CoercionImplicit = 1, - CoercionAssignment = 2, - CoercionExplicit = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CoercionForm { - Undefined = 0, - CoerceExplicitCall = 1, - CoerceExplicitCast = 2, - CoerceImplicitCast = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum BoolExprType { - Undefined = 0, - AndExpr = 1, - OrExpr = 2, - NotExpr = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SubLinkType { - Undefined = 0, - ExistsSublink = 1, - AllSublink = 2, - AnySublink = 3, - RowcompareSublink = 4, - ExprSublink = 5, - MultiexprSublink = 6, - ArraySublink = 7, - CteSublink = 8, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RowCompareType { - Undefined = 0, - RowcompareLt = 1, - RowcompareLe = 2, - RowcompareEq = 3, - RowcompareGe = 4, - RowcompareGt = 5, - RowcompareNe = 6, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum MinMaxOp { - Undefined = 0, - IsGreatest = 1, - IsLeast = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SqlValueFunctionOp { - SqlvalueFunctionOpUndefined = 0, - SvfopCurrentDate = 1, - SvfopCurrentTime = 2, - SvfopCurrentTimeN = 3, - SvfopCurrentTimestamp = 4, - SvfopCurrentTimestampN = 5, - SvfopLocaltime = 6, - SvfopLocaltimeN = 7, - SvfopLocaltimestamp = 8, - SvfopLocaltimestampN = 9, - SvfopCurrentRole = 10, - SvfopCurrentUser = 11, - SvfopUser = 12, - SvfopSessionUser = 13, - SvfopCurrentCatalog = 14, - SvfopCurrentSchema = 15, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum XmlExprOp { - Undefined = 0, - IsXmlconcat = 1, - IsXmlelement = 2, - IsXmlforest = 3, - IsXmlparse = 4, - IsXmlpi = 5, - IsXmlroot = 6, - IsXmlserialize = 7, - IsDocument = 8, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum XmlOptionType { - Undefined = 0, - XmloptionDocument = 1, - XmloptionContent = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum NullTestType { - Undefined = 0, - IsNull = 1, - IsNotNull = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum BoolTestType { - Undefined = 0, - IsTrue = 1, - IsNotTrue = 2, - IsFalse = 3, - IsNotFalse = 4, - IsUnknown = 5, - IsNotUnknown = 6, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CmdType { - Undefined = 0, - CmdUnknown = 1, - CmdSelect = 2, - CmdUpdate = 3, - CmdInsert = 4, - CmdDelete = 5, - CmdUtility = 6, - CmdNothing = 7, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum JoinType { - Undefined = 0, - JoinInner = 1, - JoinLeft = 2, - JoinFull = 3, - JoinRight = 4, - JoinSemi = 5, - JoinAnti = 6, - JoinUniqueOuter = 7, - JoinUniqueInner = 8, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AggStrategy { - Undefined = 0, - AggPlain = 1, - AggSorted = 2, - AggHashed = 3, - AggMixed = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AggSplit { - Undefined = 0, - AggsplitSimple = 1, - AggsplitInitialSerial = 2, - AggsplitFinalDeserial = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SetOpCmd { - Undefined = 0, - SetopcmdIntersect = 1, - SetopcmdIntersectAll = 2, - SetopcmdExcept = 3, - SetopcmdExceptAll = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SetOpStrategy { - Undefined = 0, - SetopSorted = 1, - SetopHashed = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum OnConflictAction { - Undefined = 0, - OnconflictNone = 1, - OnconflictNothing = 2, - OnconflictUpdate = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LimitOption { - Undefined = 0, - Default = 1, - Count = 2, - WithTies = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LockClauseStrength { - Undefined = 0, - LcsNone = 1, - LcsForkeyshare = 2, - LcsForshare = 3, - LcsFornokeyupdate = 4, - LcsForupdate = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LockWaitPolicy { - Undefined = 0, - LockWaitBlock = 1, - LockWaitSkip = 2, - LockWaitError = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LockTupleMode { - Undefined = 0, - LockTupleKeyShare = 1, - LockTupleShare = 2, - LockTupleNoKeyExclusive = 3, - LockTupleExclusive = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum KeywordKind { - NoKeyword = 0, - UnreservedKeyword = 1, - ColNameKeyword = 2, - TypeFuncNameKeyword = 3, - ReservedKeyword = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum Token { - Nul = 0, - /// Single-character tokens that are returned 1:1 (identical with "self" list in scan.l) - /// Either supporting syntax, or single-character operators (some can be both) - /// Also see <https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-SPECIAL-CHARS> - /// - /// "%" - Ascii37 = 37, - /// "(" - Ascii40 = 40, - /// ")" - Ascii41 = 41, - /// "*" - Ascii42 = 42, - /// "+" - Ascii43 = 43, - /// "," - Ascii44 = 44, - /// "-" - Ascii45 = 45, - /// "." - Ascii46 = 46, - /// "/" - Ascii47 = 47, - /// ":" - Ascii58 = 58, - /// ";" - Ascii59 = 59, - /// "<" - Ascii60 = 60, - /// "=" - Ascii61 = 61, - /// ">" - Ascii62 = 62, - /// "?" - Ascii63 = 63, - /// "[" - Ascii91 = 91, - /// "\" - Ascii92 = 92, - /// "]" - Ascii93 = 93, - /// "^" - Ascii94 = 94, - /// Named tokens in scan.l - Ident = 258, - Uident = 259, - Fconst = 260, - Sconst = 261, - Usconst = 262, - Bconst = 263, - Xconst = 264, - Op = 265, - Iconst = 266, - Param = 267, - Typecast = 268, - DotDot = 269, - ColonEquals = 270, - EqualsGreater = 271, - LessEquals = 272, - GreaterEquals = 273, - NotEquals = 274, - SqlComment = 275, - CComment = 276, - AbortP = 277, - AbsoluteP = 278, - Access = 279, - Action = 280, - AddP = 281, - Admin = 282, - After = 283, - Aggregate = 284, - All = 285, - Also = 286, - Alter = 287, - Always = 288, - Analyse = 289, - Analyze = 290, - And = 291, - Any = 292, - Array = 293, - As = 294, - Asc = 295, - Assertion = 296, - Assignment = 297, - Asymmetric = 298, - At = 299, - Attach = 300, - Attribute = 301, - Authorization = 302, - Backward = 303, - Before = 304, - BeginP = 305, - Between = 306, - Bigint = 307, - Binary = 308, - Bit = 309, - BooleanP = 310, - Both = 311, - By = 312, - Cache = 313, - Call = 314, - Called = 315, - Cascade = 316, - Cascaded = 317, - Case = 318, - Cast = 319, - CatalogP = 320, - Chain = 321, - CharP = 322, - Character = 323, - Characteristics = 324, - Check = 325, - Checkpoint = 326, - Class = 327, - Close = 328, - Cluster = 329, - Coalesce = 330, - Collate = 331, - Collation = 332, - Column = 333, - Columns = 334, - Comment = 335, - Comments = 336, - Commit = 337, - Committed = 338, - Concurrently = 339, - Configuration = 340, - Conflict = 341, - Connection = 342, - Constraint = 343, - Constraints = 344, - ContentP = 345, - ContinueP = 346, - ConversionP = 347, - Copy = 348, - Cost = 349, - Create = 350, - Cross = 351, - Csv = 352, - Cube = 353, - CurrentP = 354, - CurrentCatalog = 355, - CurrentDate = 356, - CurrentRole = 357, - CurrentSchema = 358, - CurrentTime = 359, - CurrentTimestamp = 360, - CurrentUser = 361, - Cursor = 362, - Cycle = 363, - DataP = 364, - Database = 365, - DayP = 366, - Deallocate = 367, - Dec = 368, - DecimalP = 369, - Declare = 370, - Default = 371, - Defaults = 372, - Deferrable = 373, - Deferred = 374, - Definer = 375, - DeleteP = 376, - Delimiter = 377, - Delimiters = 378, - Depends = 379, - Desc = 380, - Detach = 381, - Dictionary = 382, - DisableP = 383, - Discard = 384, - Distinct = 385, - Do = 386, - DocumentP = 387, - DomainP = 388, - DoubleP = 389, - Drop = 390, - Each = 391, - Else = 392, - EnableP = 393, - Encoding = 394, - Encrypted = 395, - EndP = 396, - EnumP = 397, - Escape = 398, - Event = 399, - Except = 400, - Exclude = 401, - Excluding = 402, - Exclusive = 403, - Execute = 404, - Exists = 405, - Explain = 406, - Expression = 407, - Extension = 408, - External = 409, - Extract = 410, - FalseP = 411, - Family = 412, - Fetch = 413, - Filter = 414, - FirstP = 415, - FloatP = 416, - Following = 417, - For = 418, - Force = 419, - Foreign = 420, - Forward = 421, - Freeze = 422, - From = 423, - Full = 424, - Function = 425, - Functions = 426, - Generated = 427, - Global = 428, - Grant = 429, - Granted = 430, - Greatest = 431, - GroupP = 432, - Grouping = 433, - Groups = 434, - Handler = 435, - Having = 436, - HeaderP = 437, - Hold = 438, - HourP = 439, - IdentityP = 440, - IfP = 441, - Ilike = 442, - Immediate = 443, - Immutable = 444, - ImplicitP = 445, - ImportP = 446, - InP = 447, - Include = 448, - Including = 449, - Increment = 450, - Index = 451, - Indexes = 452, - Inherit = 453, - Inherits = 454, - Initially = 455, - InlineP = 456, - InnerP = 457, - Inout = 458, - InputP = 459, - Insensitive = 460, - Insert = 461, - Instead = 462, - IntP = 463, - Integer = 464, - Intersect = 465, - Interval = 466, - Into = 467, - Invoker = 468, - Is = 469, - Isnull = 470, - Isolation = 471, - Join = 472, - Key = 473, - Label = 474, - Language = 475, - LargeP = 476, - LastP = 477, - LateralP = 478, - Leading = 479, - Leakproof = 480, - Least = 481, - Left = 482, - Level = 483, - Like = 484, - Limit = 485, - Listen = 486, - Load = 487, - Local = 488, - Localtime = 489, - Localtimestamp = 490, - Location = 491, - LockP = 492, - Locked = 493, - Logged = 494, - Mapping = 495, - Match = 496, - Materialized = 497, - Maxvalue = 498, - Method = 499, - MinuteP = 500, - Minvalue = 501, - Mode = 502, - MonthP = 503, - Move = 504, - NameP = 505, - Names = 506, - National = 507, - Natural = 508, - Nchar = 509, - New = 510, - Next = 511, - Nfc = 512, - Nfd = 513, - Nfkc = 514, - Nfkd = 515, - No = 516, - None = 517, - Normalize = 518, - Normalized = 519, - Not = 520, - Nothing = 521, - Notify = 522, - Notnull = 523, - Nowait = 524, - NullP = 525, - Nullif = 526, - NullsP = 527, - Numeric = 528, - ObjectP = 529, - Of = 530, - Off = 531, - Offset = 532, - Oids = 533, - Old = 534, - On = 535, - Only = 536, - Operator = 537, - Option = 538, - Options = 539, - Or = 540, - Order = 541, - Ordinality = 542, - Others = 543, - OutP = 544, - OuterP = 545, - Over = 546, - Overlaps = 547, - Overlay = 548, - Overriding = 549, - Owned = 550, - Owner = 551, - Parallel = 552, - Parser = 553, - Partial = 554, - Partition = 555, - Passing = 556, - Password = 557, - Placing = 558, - Plans = 559, - Policy = 560, - Position = 561, - Preceding = 562, - Precision = 563, - Preserve = 564, - Prepare = 565, - Prepared = 566, - Primary = 567, - Prior = 568, - Privileges = 569, - Procedural = 570, - Procedure = 571, - Procedures = 572, - Program = 573, - Publication = 574, - Quote = 575, - Range = 576, - Read = 577, - Real = 578, - Reassign = 579, - Recheck = 580, - Recursive = 581, - Ref = 582, - References = 583, - Referencing = 584, - Refresh = 585, - Reindex = 586, - RelativeP = 587, - Release = 588, - Rename = 589, - Repeatable = 590, - Replace = 591, - Replica = 592, - Reset = 593, - Restart = 594, - Restrict = 595, - Returning = 596, - Returns = 597, - Revoke = 598, - Right = 599, - Role = 600, - Rollback = 601, - Rollup = 602, - Routine = 603, - Routines = 604, - Row = 605, - Rows = 606, - Rule = 607, - Savepoint = 608, - Schema = 609, - Schemas = 610, - Scroll = 611, - Search = 612, - SecondP = 613, - Security = 614, - Select = 615, - Sequence = 616, - Sequences = 617, - Serializable = 618, - Server = 619, - Session = 620, - SessionUser = 621, - Set = 622, - Sets = 623, - Setof = 624, - Share = 625, - Show = 626, - Similar = 627, - Simple = 628, - Skip = 629, - Smallint = 630, - Snapshot = 631, - Some = 632, - SqlP = 633, - Stable = 634, - StandaloneP = 635, - Start = 636, - Statement = 637, - Statistics = 638, - Stdin = 639, - Stdout = 640, - Storage = 641, - Stored = 642, - StrictP = 643, - StripP = 644, - Subscription = 645, - Substring = 646, - Support = 647, - Symmetric = 648, - Sysid = 649, - SystemP = 650, - Table = 651, - Tables = 652, - Tablesample = 653, - Tablespace = 654, - Temp = 655, - Template = 656, - Temporary = 657, - TextP = 658, - Then = 659, - Ties = 660, - Time = 661, - Timestamp = 662, - To = 663, - Trailing = 664, - Transaction = 665, - Transform = 666, - Treat = 667, - Trigger = 668, - Trim = 669, - TrueP = 670, - Truncate = 671, - Trusted = 672, - TypeP = 673, - TypesP = 674, - Uescape = 675, - Unbounded = 676, - Uncommitted = 677, - Unencrypted = 678, - Union = 679, - Unique = 680, - Unknown = 681, - Unlisten = 682, - Unlogged = 683, - Until = 684, - Update = 685, - User = 686, - Using = 687, - Vacuum = 688, - Valid = 689, - Validate = 690, - Validator = 691, - ValueP = 692, - Values = 693, - Varchar = 694, - Variadic = 695, - Varying = 696, - Verbose = 697, - VersionP = 698, - View = 699, - Views = 700, - Volatile = 701, - When = 702, - Where = 703, - WhitespaceP = 704, - Window = 705, - With = 706, - Within = 707, - Without = 708, - Work = 709, - Wrapper = 710, - Write = 711, - XmlP = 712, - Xmlattributes = 713, - Xmlconcat = 714, - Xmlelement = 715, - Xmlexists = 716, - Xmlforest = 717, - Xmlnamespaces = 718, - Xmlparse = 719, - Xmlpi = 720, - Xmlroot = 721, - Xmlserialize = 722, - Xmltable = 723, - YearP = 724, - YesP = 725, - Zone = 726, - NotLa = 727, - NullsLa = 728, - WithLa = 729, - Postfixop = 730, - Uminus = 731, -} diff --git a/src/tools/rustfmt/tests/target/closure.rs b/src/tools/rustfmt/tests/target/closure.rs index f3107d19c2fbf..e8b4ff7a96bb8 100644 --- a/src/tools/rustfmt/tests/target/closure.rs +++ b/src/tools/rustfmt/tests/target/closure.rs @@ -71,6 +71,12 @@ fn main() { a } }); + + for<> || -> () {}; + for<> || -> () {}; + for<> || -> () {}; + + for<'a, 'b, 'c> |_: &'a (), _: &'b (), _: &'c ()| -> () {}; } fn issue311() { diff --git a/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/100.rs b/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/100.rs new file mode 100644 index 0000000000000..c010a28aab615 --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/100.rs @@ -0,0 +1,16 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-doc_comment_code_block_width: 100 + +/// ```rust +/// impl Test { +/// pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { +/// Self::from_bytes_manual_slice(v, 0, v.len()) +/// } +/// } +/// ``` + +impl Test { + pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { + Self::from_bytes_manual_slice(v, 0, v.len()) + } +} diff --git a/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/100_greater_max_width.rs b/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/100_greater_max_width.rs new file mode 100644 index 0000000000000..6bcb99b915ff9 --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/100_greater_max_width.rs @@ -0,0 +1,29 @@ +// rustfmt-max_width: 50 +// rustfmt-format_code_in_doc_comments: true +// rustfmt-doc_comment_code_block_width: 100 + +/// ```rust +/// impl Test { +/// pub const fn from_bytes( +/// v: &[u8], +/// ) -> Result<Self, ParserError> { +/// Self::from_bytes_manual_slice( +/// v, +/// 0, +/// v.len(), +/// ) +/// } +/// } +/// ``` + +impl Test { + pub const fn from_bytes( + v: &[u8], + ) -> Result<Self, ParserError> { + Self::from_bytes_manual_slice( + v, + 0, + v.len(), + ) + } +} diff --git a/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/50.rs b/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/50.rs new file mode 100644 index 0000000000000..e8ab6f28bdc5a --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/doc_comment_code_block_width/50.rs @@ -0,0 +1,22 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-doc_comment_code_block_width: 50 + +/// ```rust +/// impl Test { +/// pub const fn from_bytes( +/// v: &[u8], +/// ) -> Result<Self, ParserError> { +/// Self::from_bytes_manual_slice( +/// v, +/// 0, +/// v.len(), +/// ) +/// } +/// } +/// ``` + +impl Test { + pub const fn from_bytes(v: &[u8]) -> Result<Self, ParserError> { + Self::from_bytes_manual_slice(v, 0, v.len()) + } +} diff --git a/src/tools/rustfmt/tests/target/imports_raw_identifiers/version_One.rs b/src/tools/rustfmt/tests/target/imports_raw_identifiers/version_One.rs new file mode 100644 index 0000000000000..bc4b5b135696a --- /dev/null +++ b/src/tools/rustfmt/tests/target/imports_raw_identifiers/version_One.rs @@ -0,0 +1,5 @@ +// rustfmt-version:One + +use websocket::client::ClientBuilder; +use websocket::r#async::futures::Stream; +use websocket::result::WebSocketError; diff --git a/src/tools/rustfmt/tests/target/imports_raw_identifiers/version_Two.rs b/src/tools/rustfmt/tests/target/imports_raw_identifiers/version_Two.rs new file mode 100644 index 0000000000000..22bfe93122f95 --- /dev/null +++ b/src/tools/rustfmt/tests/target/imports_raw_identifiers/version_Two.rs @@ -0,0 +1,5 @@ +// rustfmt-version:Two + +use websocket::r#async::futures::Stream; +use websocket::client::ClientBuilder; +use websocket::result::WebSocketError; diff --git a/src/tools/rustfmt/tests/target/issue_5399.rs b/src/tools/rustfmt/tests/target/issue_5399.rs new file mode 100644 index 0000000000000..17364c38919a2 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5399.rs @@ -0,0 +1,48 @@ +// rustfmt-max_width: 140 + +impl NotificationRepository { + fn set_status_changed( + &self, + repo_tx_conn: &RepoTxConn, + rid: &RoutableId, + changed_at: NaiveDateTime, + ) -> NukeResult<Option<NotificationStatus>> { + repo_tx_conn.run(move |conn| { + let res = diesel::update(client_notification::table) + .filter( + client_notification::routable_id.eq(DieselRoutableId(rid.clone())).and( + client_notification::changed_at + .lt(changed_at) + .or(client_notification::changed_at.is_null()), + ), + ) + .set(client_notification::changed_at.eq(changed_at)) + .returning(( + client_notification::id, + client_notification::changed_at, + client_notification::polled_at, + client_notification::notified_at, + )) + .get_result::<(Uuid, Option<NaiveDateTime>, Option<NaiveDateTime>, Option<NaiveDateTime>)>(conn) + .optional()?; + + match res { + Some(row) => { + let client_id = client_contract::table + .inner_join(client_notification::table) + .filter(client_notification::id.eq(row.0)) + .select(client_contract::client_id) + .get_result::<Uuid>(conn)?; + + Ok(Some(NotificationStatus { + client_id: client_id.into(), + changed_at: row.1, + polled_at: row.2, + notified_at: row.3, + })) + } + None => Ok(None), + } + }) + } +} diff --git a/src/tools/rustfmt/tests/target/performance/issue-4476.rs b/src/tools/rustfmt/tests/target/performance/issue-4476.rs deleted file mode 100644 index 30567f2644b74..0000000000000 --- a/src/tools/rustfmt/tests/target/performance/issue-4476.rs +++ /dev/null @@ -1,705 +0,0 @@ -use super::SemverParser; - -#[allow(dead_code, non_camel_case_types)] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Rule { - EOI, - range_set, - logical_or, - range, - empty, - hyphen, - simple, - primitive, - primitive_op, - partial, - xr, - xr_op, - nr, - tilde, - caret, - qualifier, - parts, - part, - space, -} -#[allow(clippy::all)] -impl ::pest::Parser<Rule> for SemverParser { - fn parse<'i>( - rule: Rule, - input: &'i str, - ) -> ::std::result::Result<::pest::iterators::Pairs<'i, Rule>, ::pest::error::Error<Rule>> { - mod rules { - pub mod hidden { - use super::super::Rule; - #[inline] - #[allow(dead_code, non_snake_case, unused_variables)] - pub fn skip( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - Ok(state) - } - } - pub mod visible { - use super::super::Rule; - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn range_set( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::range_set, |state| { - state.sequence(|state| { - self::SOI(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::range(state)) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .sequence(|state| { - self::logical_or(state) - .and_then(|state| { - super::hidden::skip(state) - }) - .and_then(|state| self::range(state)) - }) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then( - |state| { - state.sequence(|state| { - self::logical_or(state) - .and_then(|state| { - super::hidden::skip( - state, - ) - }) - .and_then(|state| { - self::range(state) - }) - }) - }, - ) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::EOI(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn logical_or( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::logical_or, |state| { - state.sequence(|state| { - state - .sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| state.match_string("||")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn range( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::range, |state| { - self::hyphen(state) - .or_else(|state| { - state.sequence(|state| { - self::simple(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .sequence(|state| { - state - .optional(|state| { - state.match_string(",") - }) - .and_then(|state| { - super::hidden::skip(state) - }) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| { - super::hidden::skip(state) - }) - .and_then(|state| { - self::simple(state) - }) - }) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| { - state.sequence( - |state| { - state - .optional(|state| state.match_string(",")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::simple(state)) - }, - ) - }) - }) - }) - }) - }) - }) - }) - }) - }) - .or_else(|state| self::empty(state)) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn empty( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::empty, |state| state.match_string("")) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn hyphen( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::hyphen, |state| { - state.sequence(|state| { - self::partial(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| { - self::space(state) - }) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| state.match_string("-")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - self::space(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| { - self::space(state) - }) - }) - }) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn simple( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::simple, |state| { - self::primitive(state) - .or_else(|state| self::partial(state)) - .or_else(|state| self::tilde(state)) - .or_else(|state| self::caret(state)) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn primitive( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::primitive, |state| { - state.sequence(|state| { - self::primitive_op(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn primitive_op( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::primitive_op, |state| { - state - .match_string("<=") - .or_else(|state| state.match_string(">=")) - .or_else(|state| state.match_string(">")) - .or_else(|state| state.match_string("<")) - .or_else(|state| state.match_string("=")) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn partial( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::partial, |state| { - state.sequence(|state| { - self::xr(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.optional(|state| { - state.sequence(|state| { - state - .match_string(".") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::xr(state)) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.optional(|state| { - state.sequence(|state| { - state - .match_string(".") - .and_then(|state| { - super::hidden::skip(state) - }) - .and_then(|state| self::xr(state)) - .and_then(|state| { - super::hidden::skip(state) - }) - .and_then(|state| { - state.optional(|state| { - self::qualifier(state) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn xr( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::xr, |state| { - self::xr_op(state).or_else(|state| self::nr(state)) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn xr_op( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::xr_op, |state| { - state - .match_string("x") - .or_else(|state| state.match_string("X")) - .or_else(|state| state.match_string("*")) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn nr( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::nr, |state| { - state.match_string("0").or_else(|state| { - state.sequence(|state| { - state - .match_range('1'..'9') - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state.match_range('0'..'9').and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then( - |state| state.match_range('0'..'9'), - ) - }) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn tilde( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::tilde, |state| { - state.sequence(|state| { - state - .match_string("~>") - .or_else(|state| state.match_string("~")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn caret( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::caret, |state| { - state.sequence(|state| { - state - .match_string("^") - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - self::space(state).and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state) - .and_then(|state| self::space(state)) - }) - }) - }) - }) - }) - }) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::partial(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn qualifier( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::qualifier, |state| { - state.sequence(|state| { - state - .match_string("-") - .or_else(|state| state.match_string("+")) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| self::parts(state)) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn parts( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::parts, |state| { - state.sequence(|state| { - self::part(state) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .sequence(|state| { - state - .match_string(".") - .and_then(|state| { - super::hidden::skip(state) - }) - .and_then(|state| self::part(state)) - }) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then( - |state| { - state.sequence(|state| { - state - .match_string(".") - .and_then(|state| { - super::hidden::skip( - state, - ) - }) - .and_then(|state| { - self::part(state) - }) - }) - }, - ) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn part( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::part, |state| { - self::nr(state).or_else(|state| { - state.sequence(|state| { - state - .match_string("-") - .or_else(|state| state.match_range('0'..'9')) - .or_else(|state| state.match_range('A'..'Z')) - .or_else(|state| state.match_range('a'..'z')) - .and_then(|state| super::hidden::skip(state)) - .and_then(|state| { - state.sequence(|state| { - state.optional(|state| { - state - .match_string("-") - .or_else(|state| state.match_range('0'..'9')) - .or_else(|state| state.match_range('A'..'Z')) - .or_else(|state| state.match_range('a'..'z')) - .and_then(|state| { - state.repeat(|state| { - state.sequence(|state| { - super::hidden::skip(state).and_then( - |state| { - state - .match_string("-") - .or_else(|state| { - state.match_range( - '0'..'9', - ) - }) - .or_else(|state| { - state.match_range( - 'A'..'Z', - ) - }) - .or_else(|state| { - state.match_range( - 'a'..'z', - ) - }) - }, - ) - }) - }) - }) - }) - }) - }) - }) - }) - }) - } - #[inline] - #[allow(non_snake_case, unused_variables)] - pub fn space( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state - .match_string(" ") - .or_else(|state| state.match_string("\t")) - } - #[inline] - #[allow(dead_code, non_snake_case, unused_variables)] - pub fn EOI( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.rule(Rule::EOI, |state| state.end_of_input()) - } - #[inline] - #[allow(dead_code, non_snake_case, unused_variables)] - pub fn SOI( - state: Box<::pest::ParserState<Rule>>, - ) -> ::pest::ParseResult<Box<::pest::ParserState<Rule>>> { - state.start_of_input() - } - } - pub use self::visible::*; - } - ::pest::state(input, |state| match rule { - Rule::range_set => rules::range_set(state), - Rule::logical_or => rules::logical_or(state), - Rule::range => rules::range(state), - Rule::empty => rules::empty(state), - Rule::hyphen => rules::hyphen(state), - Rule::simple => rules::simple(state), - Rule::primitive => rules::primitive(state), - Rule::primitive_op => rules::primitive_op(state), - Rule::partial => rules::partial(state), - Rule::xr => rules::xr(state), - Rule::xr_op => rules::xr_op(state), - Rule::nr => rules::nr(state), - Rule::tilde => rules::tilde(state), - Rule::caret => rules::caret(state), - Rule::qualifier => rules::qualifier(state), - Rule::parts => rules::parts(state), - Rule::part => rules::part(state), - Rule::space => rules::space(state), - Rule::EOI => rules::EOI(state), - }) - } -} diff --git a/src/tools/rustfmt/tests/target/performance/issue-4867.rs b/src/tools/rustfmt/tests/target/performance/issue-4867.rs deleted file mode 100644 index 336dae1b64ab8..0000000000000 --- a/src/tools/rustfmt/tests/target/performance/issue-4867.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod modA { - mod modB { - mod modC { - mod modD { - mod modE { - fn func() { - state . rule (Rule :: myrule , | state | { state . sequence (| state | { state . sequence (| state | { state . match_string ("abc") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . match_string ("def") }) }) . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . sequence (| state | { state . optional (| state | { state . sequence (| state | { state . match_string ("abc") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . match_string ("def") }) }) . and_then (| state | { state . repeat (| state | { state . sequence (| state | { super :: hidden :: skip (state) . and_then (| state | { state . sequence (| state | { state . match_string ("abc") . and_then (| state | { super :: hidden :: skip (state) }) . and_then (| state | { state . match_string ("def") }) }) }) }) }) }) }) }) }) }) }); - } - } - } - } - } -} diff --git a/src/tools/rustfmt/tests/target/performance/issue-5128.rs b/src/tools/rustfmt/tests/target/performance/issue-5128.rs deleted file mode 100644 index ba9ebfc6243f2..0000000000000 --- a/src/tools/rustfmt/tests/target/performance/issue-5128.rs +++ /dev/null @@ -1,4898 +0,0 @@ -fn takes_a_long_time_to_rustfmt() { - let inner_cte = vec![Node { - node: Some(node::Node::CommonTableExpr(Box::new(CommonTableExpr { - ctename: String::from("ranked_by_age_within_key"), - aliascolnames: vec![], - ctematerialized: CteMaterialize::Default as i32, - ctequery: Some(Box::new(Node { - node: Some(node::Node::SelectStmt(Box::new(SelectStmt { - distinct_clause: vec![], - into_clause: None, - target_list: vec![ - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from(""), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::AStar(AStar {})), - }], - location: 80, - })), - })), - location: 80, - }))), - }, - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from("rank_in_key"), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::FuncCall(Box::new(FuncCall { - funcname: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("row_number"), - })), - }], - args: vec![], - agg_order: vec![], - agg_filter: None, - agg_within_group: false, - agg_star: false, - agg_distinct: false, - func_variadic: false, - over: Some(Box::new(WindowDef { - name: String::from(""), - refname: String::from(""), - partition_clause: vec![Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("synthetic_key"), - })), - }], - location: 123, - })), - }], - order_clause: vec![Node { - node: Some(node::Node::SortBy(Box::new(SortBy { - node: Some(Box::new(Node { - node: Some(node::Node::ColumnRef( - ColumnRef { - fields: vec![Node { - node: Some(node::Node::String( - String2 { - str: String::from( - "logical_timestamp", - ), - }, - )), - }], - location: 156, - }, - )), - })), - sortby_dir: SortByDir::SortbyDesc as i32, - sortby_nulls: SortByNulls::SortbyNullsDefault - as i32, - use_op: vec![], - location: -1, - }))), - }], - frame_options: 1058, - start_offset: None, - end_offset: None, - location: 109, - })), - location: 91, - }))), - })), - location: 91, - }))), - }, - ], - from_clause: vec![Node { - node: Some(node::Node::RangeVar(RangeVar { - catalogname: String::from(""), - schemaname: String::from("_supertables"), - relname: String::from("9999-9999-9999"), - inh: true, - relpersistence: String::from("p"), - alias: None, - location: 206, - })), - }], - where_clause: Some(Box::new(Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("<="), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("logical_timestamp"), - })), - }], - location: 250, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new(AConst { - val: Some(Box::new(Node { - node: Some(node::Node::Integer(Integer { ival: 9000 })), - })), - location: 271, - }))), - })), - location: 268, - }))), - })), - group_clause: vec![], - having_clause: None, - window_clause: vec![], - values_lists: vec![], - sort_clause: vec![], - limit_offset: None, - limit_count: None, - limit_option: LimitOption::Default as i32, - locking_clause: vec![], - with_clause: None, - op: SetOperation::SetopNone as i32, - all: false, - larg: None, - rarg: None, - }))), - })), - location: 29, - cterecursive: false, - cterefcount: 0, - ctecolnames: vec![], - ctecoltypes: vec![], - ctecoltypmods: vec![], - ctecolcollations: vec![], - }))), - }]; - let outer_cte = vec![Node { - node: Some(node::Node::CommonTableExpr(Box::new(CommonTableExpr { - ctename: String::from("table_name"), - aliascolnames: vec![], - ctematerialized: CteMaterialize::Default as i32, - ctequery: Some(Box::new(Node { - node: Some(node::Node::SelectStmt(Box::new(SelectStmt { - distinct_clause: vec![], - into_clause: None, - target_list: vec![ - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from("column1"), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("c1"), - })), - }], - location: 301, - })), - })), - location: 301, - }))), - }, - Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from("column2"), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("c2"), - })), - }], - location: 324, - })), - })), - location: 324, - }))), - }, - ], - from_clause: vec![Node { - node: Some(node::Node::RangeVar(RangeVar { - catalogname: String::from(""), - schemaname: String::from(""), - relname: String::from("ranked_by_age_within_key"), - inh: true, - relpersistence: String::from("p"), - alias: None, - location: 347, - })), - }], - where_clause: Some(Box::new(Node { - node: Some(node::Node::BoolExpr(Box::new(BoolExpr { - xpr: None, - boolop: BoolExprType::AndExpr as i32, - args: vec![ - Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("="), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("rank_in_key"), - })), - }], - location: 382, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new(AConst { - val: Some(Box::new(Node { - node: Some(node::Node::Integer(Integer { - ival: 1, - })), - })), - location: 396, - }))), - })), - location: 394, - }))), - }, - Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("="), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("is_deleted"), - })), - }], - location: 402, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::TypeCast(Box::new(TypeCast { - arg: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new( - AConst { - val: Some(Box::new(Node { - node: Some(node::Node::String( - String2 { - str: String::from("f"), - }, - )), - })), - location: 415, - }, - ))), - })), - type_name: Some(TypeName { - names: vec![ - Node { - node: Some(node::Node::String( - String2 { - str: String::from("pg_catalog"), - }, - )), - }, - Node { - node: Some(node::Node::String( - String2 { - str: String::from("bool"), - }, - )), - }, - ], - type_oid: 0, - setof: false, - pct_type: false, - typmods: vec![], - typemod: -1, - array_bounds: vec![], - location: -1, - }), - location: -1, - }))), - })), - location: 413, - }))), - }, - ], - location: 398, - }))), - })), - group_clause: vec![], - having_clause: None, - window_clause: vec![], - values_lists: vec![], - sort_clause: vec![], - limit_offset: None, - limit_count: None, - limit_option: LimitOption::Default as i32, - locking_clause: vec![], - with_clause: Some(WithClause { - ctes: inner_cte, - recursive: false, - location: 24, - }), - op: SetOperation::SetopNone as i32, - all: false, - larg: None, - rarg: None, - }))), - })), - location: 5, - cterecursive: false, - cterefcount: 0, - ctecolnames: vec![], - ctecoltypes: vec![], - ctecoltypmods: vec![], - ctecolcollations: vec![], - }))), - }]; - let expected_result = ParseResult { - version: 130003, - stmts: vec![RawStmt { - stmt: Some(Box::new(Node { - node: Some(node::Node::SelectStmt(Box::new(SelectStmt { - distinct_clause: vec![], - into_clause: None, - - target_list: vec![Node { - node: Some(node::Node::ResTarget(Box::new(ResTarget { - name: String::from(""), - indirection: vec![], - val: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("column1"), - })), - }], - location: 430, - })), - })), - location: 430, - }))), - }], - from_clause: vec![Node { - node: Some(node::Node::RangeVar(RangeVar { - catalogname: String::from(""), - schemaname: String::from(""), - relname: String::from("table_name"), - inh: true, - relpersistence: String::from("p"), - alias: None, - location: 443, - })), - }], - where_clause: Some(Box::new(Node { - node: Some(node::Node::AExpr(Box::new(AExpr { - kind: AExprKind::AexprOp as i32, - name: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from(">"), - })), - }], - lexpr: Some(Box::new(Node { - node: Some(node::Node::ColumnRef(ColumnRef { - fields: vec![Node { - node: Some(node::Node::String(String2 { - str: String::from("column2"), - })), - }], - location: 460, - })), - })), - rexpr: Some(Box::new(Node { - node: Some(node::Node::AConst(Box::new(AConst { - val: Some(Box::new(Node { - node: Some(node::Node::Integer(Integer { ival: 9000 })), - })), - location: 470, - }))), - })), - location: 468, - }))), - })), - group_clause: vec![], - having_clause: None, - window_clause: vec![], - values_lists: vec![], - sort_clause: vec![], - limit_offset: None, - limit_count: None, - limit_option: LimitOption::Default as i32, - locking_clause: vec![], - with_clause: Some(WithClause { - ctes: outer_cte, - recursive: false, - location: 0, - }), - op: SetOperation::SetopNone as i32, - all: false, - larg: None, - rarg: None, - }))), - })), - stmt_location: 0, - stmt_len: 0, - }], - }; -} -#[derive(Clone, PartialEq)] -pub struct ParseResult { - pub version: i32, - - pub stmts: Vec<RawStmt>, -} -#[derive(Clone, PartialEq)] -pub struct ScanResult { - pub version: i32, - - pub tokens: Vec<ScanToken>, -} -#[derive(Clone, PartialEq)] -pub struct Node { - pub node: ::core::option::Option<node::Node>, -} -/// Nested message and enum types in `Node`. -pub mod node { - #[derive(Clone, PartialEq)] - pub enum Node { - Alias(super::Alias), - - RangeVar(super::RangeVar), - - TableFunc(Box<super::TableFunc>), - - Expr(super::Expr), - - Var(Box<super::Var>), - - Param(Box<super::Param>), - - Aggref(Box<super::Aggref>), - - GroupingFunc(Box<super::GroupingFunc>), - - WindowFunc(Box<super::WindowFunc>), - - SubscriptingRef(Box<super::SubscriptingRef>), - - FuncExpr(Box<super::FuncExpr>), - - NamedArgExpr(Box<super::NamedArgExpr>), - - OpExpr(Box<super::OpExpr>), - - DistinctExpr(Box<super::DistinctExpr>), - - NullIfExpr(Box<super::NullIfExpr>), - - ScalarArrayOpExpr(Box<super::ScalarArrayOpExpr>), - - BoolExpr(Box<super::BoolExpr>), - - SubLink(Box<super::SubLink>), - - SubPlan(Box<super::SubPlan>), - - AlternativeSubPlan(Box<super::AlternativeSubPlan>), - - FieldSelect(Box<super::FieldSelect>), - - FieldStore(Box<super::FieldStore>), - - RelabelType(Box<super::RelabelType>), - - CoerceViaIo(Box<super::CoerceViaIo>), - - ArrayCoerceExpr(Box<super::ArrayCoerceExpr>), - - ConvertRowtypeExpr(Box<super::ConvertRowtypeExpr>), - - CollateExpr(Box<super::CollateExpr>), - - CaseExpr(Box<super::CaseExpr>), - - CaseWhen(Box<super::CaseWhen>), - - CaseTestExpr(Box<super::CaseTestExpr>), - - ArrayExpr(Box<super::ArrayExpr>), - - RowExpr(Box<super::RowExpr>), - - RowCompareExpr(Box<super::RowCompareExpr>), - - CoalesceExpr(Box<super::CoalesceExpr>), - - MinMaxExpr(Box<super::MinMaxExpr>), - - SqlvalueFunction(Box<super::SqlValueFunction>), - - XmlExpr(Box<super::XmlExpr>), - - NullTest(Box<super::NullTest>), - - BooleanTest(Box<super::BooleanTest>), - - CoerceToDomain(Box<super::CoerceToDomain>), - - CoerceToDomainValue(Box<super::CoerceToDomainValue>), - - SetToDefault(Box<super::SetToDefault>), - - CurrentOfExpr(Box<super::CurrentOfExpr>), - - NextValueExpr(Box<super::NextValueExpr>), - - InferenceElem(Box<super::InferenceElem>), - - TargetEntry(Box<super::TargetEntry>), - - RangeTblRef(super::RangeTblRef), - - JoinExpr(Box<super::JoinExpr>), - - FromExpr(Box<super::FromExpr>), - - OnConflictExpr(Box<super::OnConflictExpr>), - - IntoClause(Box<super::IntoClause>), - - RawStmt(Box<super::RawStmt>), - - Query(Box<super::Query>), - - InsertStmt(Box<super::InsertStmt>), - - DeleteStmt(Box<super::DeleteStmt>), - - UpdateStmt(Box<super::UpdateStmt>), - - SelectStmt(Box<super::SelectStmt>), - - AlterTableStmt(super::AlterTableStmt), - - AlterTableCmd(Box<super::AlterTableCmd>), - - AlterDomainStmt(Box<super::AlterDomainStmt>), - - SetOperationStmt(Box<super::SetOperationStmt>), - - GrantStmt(super::GrantStmt), - - GrantRoleStmt(super::GrantRoleStmt), - - AlterDefaultPrivilegesStmt(super::AlterDefaultPrivilegesStmt), - - ClosePortalStmt(super::ClosePortalStmt), - - ClusterStmt(super::ClusterStmt), - - CopyStmt(Box<super::CopyStmt>), - - CreateStmt(super::CreateStmt), - - DefineStmt(super::DefineStmt), - - DropStmt(super::DropStmt), - - TruncateStmt(super::TruncateStmt), - - CommentStmt(Box<super::CommentStmt>), - - FetchStmt(super::FetchStmt), - - IndexStmt(Box<super::IndexStmt>), - - CreateFunctionStmt(super::CreateFunctionStmt), - - AlterFunctionStmt(super::AlterFunctionStmt), - - DoStmt(super::DoStmt), - - RenameStmt(Box<super::RenameStmt>), - - RuleStmt(Box<super::RuleStmt>), - - NotifyStmt(super::NotifyStmt), - - ListenStmt(super::ListenStmt), - - UnlistenStmt(super::UnlistenStmt), - - TransactionStmt(super::TransactionStmt), - - ViewStmt(Box<super::ViewStmt>), - - LoadStmt(super::LoadStmt), - - CreateDomainStmt(Box<super::CreateDomainStmt>), - - CreatedbStmt(super::CreatedbStmt), - - DropdbStmt(super::DropdbStmt), - - VacuumStmt(super::VacuumStmt), - - ExplainStmt(Box<super::ExplainStmt>), - - CreateTableAsStmt(Box<super::CreateTableAsStmt>), - - CreateSeqStmt(super::CreateSeqStmt), - - AlterSeqStmt(super::AlterSeqStmt), - - VariableSetStmt(super::VariableSetStmt), - - VariableShowStmt(super::VariableShowStmt), - - DiscardStmt(super::DiscardStmt), - - CreateTrigStmt(Box<super::CreateTrigStmt>), - - CreatePlangStmt(super::CreatePLangStmt), - - CreateRoleStmt(super::CreateRoleStmt), - - AlterRoleStmt(super::AlterRoleStmt), - - DropRoleStmt(super::DropRoleStmt), - - LockStmt(super::LockStmt), - - ConstraintsSetStmt(super::ConstraintsSetStmt), - - ReindexStmt(super::ReindexStmt), - - CheckPointStmt(super::CheckPointStmt), - - CreateSchemaStmt(super::CreateSchemaStmt), - - AlterDatabaseStmt(super::AlterDatabaseStmt), - - AlterDatabaseSetStmt(super::AlterDatabaseSetStmt), - - AlterRoleSetStmt(super::AlterRoleSetStmt), - - CreateConversionStmt(super::CreateConversionStmt), - - CreateCastStmt(super::CreateCastStmt), - - CreateOpClassStmt(super::CreateOpClassStmt), - - CreateOpFamilyStmt(super::CreateOpFamilyStmt), - - AlterOpFamilyStmt(super::AlterOpFamilyStmt), - - PrepareStmt(Box<super::PrepareStmt>), - - ExecuteStmt(super::ExecuteStmt), - - DeallocateStmt(super::DeallocateStmt), - - DeclareCursorStmt(Box<super::DeclareCursorStmt>), - - CreateTableSpaceStmt(super::CreateTableSpaceStmt), - - DropTableSpaceStmt(super::DropTableSpaceStmt), - - AlterObjectDependsStmt(Box<super::AlterObjectDependsStmt>), - - AlterObjectSchemaStmt(Box<super::AlterObjectSchemaStmt>), - - AlterOwnerStmt(Box<super::AlterOwnerStmt>), - - AlterOperatorStmt(super::AlterOperatorStmt), - - AlterTypeStmt(super::AlterTypeStmt), - - DropOwnedStmt(super::DropOwnedStmt), - - ReassignOwnedStmt(super::ReassignOwnedStmt), - - CompositeTypeStmt(super::CompositeTypeStmt), - - CreateEnumStmt(super::CreateEnumStmt), - - CreateRangeStmt(super::CreateRangeStmt), - - AlterEnumStmt(super::AlterEnumStmt), - - AlterTsdictionaryStmt(super::AlterTsDictionaryStmt), - - AlterTsconfigurationStmt(super::AlterTsConfigurationStmt), - - CreateFdwStmt(super::CreateFdwStmt), - - AlterFdwStmt(super::AlterFdwStmt), - - CreateForeignServerStmt(super::CreateForeignServerStmt), - - AlterForeignServerStmt(super::AlterForeignServerStmt), - - CreateUserMappingStmt(super::CreateUserMappingStmt), - - AlterUserMappingStmt(super::AlterUserMappingStmt), - - DropUserMappingStmt(super::DropUserMappingStmt), - - AlterTableSpaceOptionsStmt(super::AlterTableSpaceOptionsStmt), - - AlterTableMoveAllStmt(super::AlterTableMoveAllStmt), - - SecLabelStmt(Box<super::SecLabelStmt>), - - CreateForeignTableStmt(super::CreateForeignTableStmt), - - ImportForeignSchemaStmt(super::ImportForeignSchemaStmt), - - CreateExtensionStmt(super::CreateExtensionStmt), - - AlterExtensionStmt(super::AlterExtensionStmt), - - AlterExtensionContentsStmt(Box<super::AlterExtensionContentsStmt>), - - CreateEventTrigStmt(super::CreateEventTrigStmt), - - AlterEventTrigStmt(super::AlterEventTrigStmt), - - RefreshMatViewStmt(super::RefreshMatViewStmt), - - ReplicaIdentityStmt(super::ReplicaIdentityStmt), - - AlterSystemStmt(super::AlterSystemStmt), - - CreatePolicyStmt(Box<super::CreatePolicyStmt>), - - AlterPolicyStmt(Box<super::AlterPolicyStmt>), - - CreateTransformStmt(super::CreateTransformStmt), - - CreateAmStmt(super::CreateAmStmt), - - CreatePublicationStmt(super::CreatePublicationStmt), - - AlterPublicationStmt(super::AlterPublicationStmt), - - CreateSubscriptionStmt(super::CreateSubscriptionStmt), - - AlterSubscriptionStmt(super::AlterSubscriptionStmt), - - DropSubscriptionStmt(super::DropSubscriptionStmt), - - CreateStatsStmt(super::CreateStatsStmt), - - AlterCollationStmt(super::AlterCollationStmt), - - CallStmt(Box<super::CallStmt>), - - AlterStatsStmt(super::AlterStatsStmt), - - AExpr(Box<super::AExpr>), - - ColumnRef(super::ColumnRef), - - ParamRef(super::ParamRef), - - AConst(Box<super::AConst>), - - FuncCall(Box<super::FuncCall>), - - AStar(super::AStar), - - AIndices(Box<super::AIndices>), - - AIndirection(Box<super::AIndirection>), - - AArrayExpr(super::AArrayExpr), - - ResTarget(Box<super::ResTarget>), - - MultiAssignRef(Box<super::MultiAssignRef>), - - TypeCast(Box<super::TypeCast>), - - CollateClause(Box<super::CollateClause>), - - SortBy(Box<super::SortBy>), - - WindowDef(Box<super::WindowDef>), - - RangeSubselect(Box<super::RangeSubselect>), - - RangeFunction(super::RangeFunction), - - RangeTableSample(Box<super::RangeTableSample>), - - RangeTableFunc(Box<super::RangeTableFunc>), - - RangeTableFuncCol(Box<super::RangeTableFuncCol>), - - TypeName(super::TypeName), - - ColumnDef(Box<super::ColumnDef>), - - IndexElem(Box<super::IndexElem>), - - Constraint(Box<super::Constraint>), - - DefElem(Box<super::DefElem>), - - RangeTblEntry(Box<super::RangeTblEntry>), - - RangeTblFunction(Box<super::RangeTblFunction>), - - TableSampleClause(Box<super::TableSampleClause>), - - WithCheckOption(Box<super::WithCheckOption>), - - SortGroupClause(super::SortGroupClause), - - GroupingSet(super::GroupingSet), - - WindowClause(Box<super::WindowClause>), - - ObjectWithArgs(super::ObjectWithArgs), - - AccessPriv(super::AccessPriv), - - CreateOpClassItem(super::CreateOpClassItem), - - TableLikeClause(super::TableLikeClause), - - FunctionParameter(Box<super::FunctionParameter>), - - LockingClause(super::LockingClause), - - RowMarkClause(super::RowMarkClause), - - XmlSerialize(Box<super::XmlSerialize>), - - WithClause(super::WithClause), - - InferClause(Box<super::InferClause>), - - OnConflictClause(Box<super::OnConflictClause>), - - CommonTableExpr(Box<super::CommonTableExpr>), - - RoleSpec(super::RoleSpec), - - TriggerTransition(super::TriggerTransition), - - PartitionElem(Box<super::PartitionElem>), - - PartitionSpec(super::PartitionSpec), - - PartitionBoundSpec(super::PartitionBoundSpec), - - PartitionRangeDatum(Box<super::PartitionRangeDatum>), - - PartitionCmd(super::PartitionCmd), - - VacuumRelation(super::VacuumRelation), - - InlineCodeBlock(super::InlineCodeBlock), - - CallContext(super::CallContext), - - Integer(super::Integer), - - Float(super::Float), - - String(super::String2), - - BitString(super::BitString), - - Null(super::Null), - - List(super::List), - - IntList(super::IntList), - - OidList(super::OidList), - } -} -#[derive(Clone, PartialEq)] -pub struct Integer { - /// machine integer - pub ival: i32, -} -#[derive(Clone, PartialEq)] -pub struct Float { - /// string - pub str: String, -} -#[derive(Clone, PartialEq)] -pub struct String2 { - /// string - pub str: String, -} -#[derive(Clone, PartialEq)] -pub struct BitString { - /// string - pub str: String, -} -/// intentionally empty -#[derive(Clone, PartialEq)] -pub struct Null {} -#[derive(Clone, PartialEq)] -pub struct List { - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct OidList { - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct IntList { - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct Alias { - pub aliasname: String, - - pub colnames: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RangeVar { - pub catalogname: String, - - pub schemaname: String, - - pub relname: String, - - pub inh: bool, - - pub relpersistence: String, - - pub alias: ::core::option::Option<Alias>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct TableFunc { - pub ns_uris: Vec<Node>, - - pub ns_names: Vec<Node>, - - pub docexpr: ::core::option::Option<Box<Node>>, - - pub rowexpr: ::core::option::Option<Box<Node>>, - - pub colnames: Vec<Node>, - - pub coltypes: Vec<Node>, - - pub coltypmods: Vec<Node>, - - pub colcollations: Vec<Node>, - - pub colexprs: Vec<Node>, - - pub coldefexprs: Vec<Node>, - - pub notnulls: Vec<u64>, - - pub ordinalitycol: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct Expr {} -#[derive(Clone, PartialEq)] -pub struct Var { - pub xpr: ::core::option::Option<Box<Node>>, - - pub varno: u32, - - pub varattno: i32, - - pub vartype: u32, - - pub vartypmod: i32, - - pub varcollid: u32, - - pub varlevelsup: u32, - - pub varnosyn: u32, - - pub varattnosyn: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct Param { - pub xpr: ::core::option::Option<Box<Node>>, - - pub paramkind: i32, - - pub paramid: i32, - - pub paramtype: u32, - - pub paramtypmod: i32, - - pub paramcollid: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct Aggref { - pub xpr: ::core::option::Option<Box<Node>>, - - pub aggfnoid: u32, - - pub aggtype: u32, - - pub aggcollid: u32, - - pub inputcollid: u32, - - pub aggtranstype: u32, - - pub aggargtypes: Vec<Node>, - - pub aggdirectargs: Vec<Node>, - - pub args: Vec<Node>, - - pub aggorder: Vec<Node>, - - pub aggdistinct: Vec<Node>, - - pub aggfilter: ::core::option::Option<Box<Node>>, - - pub aggstar: bool, - - pub aggvariadic: bool, - - pub aggkind: String, - - pub agglevelsup: u32, - - pub aggsplit: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct GroupingFunc { - pub xpr: ::core::option::Option<Box<Node>>, - - pub args: Vec<Node>, - - pub refs: Vec<Node>, - - pub cols: Vec<Node>, - - pub agglevelsup: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WindowFunc { - pub xpr: ::core::option::Option<Box<Node>>, - - pub winfnoid: u32, - - pub wintype: u32, - - pub wincollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub aggfilter: ::core::option::Option<Box<Node>>, - - pub winref: u32, - - pub winstar: bool, - - pub winagg: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SubscriptingRef { - pub xpr: ::core::option::Option<Box<Node>>, - - pub refcontainertype: u32, - - pub refelemtype: u32, - - pub reftypmod: i32, - - pub refcollid: u32, - - pub refupperindexpr: Vec<Node>, - - pub reflowerindexpr: Vec<Node>, - - pub refexpr: ::core::option::Option<Box<Node>>, - - pub refassgnexpr: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct FuncExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub funcid: u32, - - pub funcresulttype: u32, - - pub funcretset: bool, - - pub funcvariadic: bool, - - pub funcformat: i32, - - pub funccollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct NamedArgExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub name: String, - - pub argnumber: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct OpExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub opresulttype: u32, - - pub opretset: bool, - - pub opcollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct DistinctExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub opresulttype: u32, - - pub opretset: bool, - - pub opcollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct NullIfExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub opresulttype: u32, - - pub opretset: bool, - - pub opcollid: u32, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ScalarArrayOpExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub opno: u32, - - pub opfuncid: u32, - - pub use_or: bool, - - pub inputcollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct BoolExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub boolop: i32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SubLink { - pub xpr: ::core::option::Option<Box<Node>>, - - pub sub_link_type: i32, - - pub sub_link_id: i32, - - pub testexpr: ::core::option::Option<Box<Node>>, - - pub oper_name: Vec<Node>, - - pub subselect: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SubPlan { - pub xpr: ::core::option::Option<Box<Node>>, - - pub sub_link_type: i32, - - pub testexpr: ::core::option::Option<Box<Node>>, - - pub param_ids: Vec<Node>, - - pub plan_id: i32, - - pub plan_name: String, - - pub first_col_type: u32, - - pub first_col_typmod: i32, - - pub first_col_collation: u32, - - pub use_hash_table: bool, - - pub unknown_eq_false: bool, - - pub parallel_safe: bool, - - pub set_param: Vec<Node>, - - pub par_param: Vec<Node>, - - pub args: Vec<Node>, - - pub startup_cost: f64, - - pub per_call_cost: f64, -} -#[derive(Clone, PartialEq)] -pub struct AlternativeSubPlan { - pub xpr: ::core::option::Option<Box<Node>>, - - pub subplans: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct FieldSelect { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub fieldnum: i32, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, -} -#[derive(Clone, PartialEq)] -pub struct FieldStore { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub newvals: Vec<Node>, - - pub fieldnums: Vec<Node>, - - pub resulttype: u32, -} -#[derive(Clone, PartialEq)] -pub struct RelabelType { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, - - pub relabelformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CoerceViaIo { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resultcollid: u32, - - pub coerceformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ArrayCoerceExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub elemexpr: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, - - pub coerceformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ConvertRowtypeExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub convertformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CollateExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub coll_oid: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CaseExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub casetype: u32, - - pub casecollid: u32, - - pub arg: ::core::option::Option<Box<Node>>, - - pub args: Vec<Node>, - - pub defresult: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CaseWhen { - pub xpr: ::core::option::Option<Box<Node>>, - - pub expr: ::core::option::Option<Box<Node>>, - - pub result: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CaseTestExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub type_id: u32, - - pub type_mod: i32, - - pub collation: u32, -} -#[derive(Clone, PartialEq)] -pub struct ArrayExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub array_typeid: u32, - - pub array_collid: u32, - - pub element_typeid: u32, - - pub elements: Vec<Node>, - - pub multidims: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RowExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub args: Vec<Node>, - - pub row_typeid: u32, - - pub row_format: i32, - - pub colnames: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RowCompareExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub rctype: i32, - - pub opnos: Vec<Node>, - - pub opfamilies: Vec<Node>, - - pub inputcollids: Vec<Node>, - - pub largs: Vec<Node>, - - pub rargs: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CoalesceExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub coalescetype: u32, - - pub coalescecollid: u32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct MinMaxExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub minmaxtype: u32, - - pub minmaxcollid: u32, - - pub inputcollid: u32, - - pub op: i32, - - pub args: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SqlValueFunction { - pub xpr: ::core::option::Option<Box<Node>>, - - pub op: i32, - - pub r#type: u32, - - pub typmod: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct XmlExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub op: i32, - - pub name: String, - - pub named_args: Vec<Node>, - - pub arg_names: Vec<Node>, - - pub args: Vec<Node>, - - pub xmloption: i32, - - pub r#type: u32, - - pub typmod: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct NullTest { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub nulltesttype: i32, - - pub argisrow: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct BooleanTest { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub booltesttype: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CoerceToDomain { - pub xpr: ::core::option::Option<Box<Node>>, - - pub arg: ::core::option::Option<Box<Node>>, - - pub resulttype: u32, - - pub resulttypmod: i32, - - pub resultcollid: u32, - - pub coercionformat: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CoerceToDomainValue { - pub xpr: ::core::option::Option<Box<Node>>, - - pub type_id: u32, - - pub type_mod: i32, - - pub collation: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SetToDefault { - pub xpr: ::core::option::Option<Box<Node>>, - - pub type_id: u32, - - pub type_mod: i32, - - pub collation: u32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CurrentOfExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub cvarno: u32, - - pub cursor_name: String, - - pub cursor_param: i32, -} -#[derive(Clone, PartialEq)] -pub struct NextValueExpr { - pub xpr: ::core::option::Option<Box<Node>>, - - pub seqid: u32, - - pub type_id: u32, -} -#[derive(Clone, PartialEq)] -pub struct InferenceElem { - pub xpr: ::core::option::Option<Box<Node>>, - - pub expr: ::core::option::Option<Box<Node>>, - - pub infercollid: u32, - - pub inferopclass: u32, -} -#[derive(Clone, PartialEq)] -pub struct TargetEntry { - pub xpr: ::core::option::Option<Box<Node>>, - - pub expr: ::core::option::Option<Box<Node>>, - - pub resno: i32, - - pub resname: String, - - pub ressortgroupref: u32, - - pub resorigtbl: u32, - - pub resorigcol: i32, - - pub resjunk: bool, -} -#[derive(Clone, PartialEq)] -pub struct RangeTblRef { - pub rtindex: i32, -} -#[derive(Clone, PartialEq)] -pub struct JoinExpr { - pub jointype: i32, - - pub is_natural: bool, - - pub larg: ::core::option::Option<Box<Node>>, - - pub rarg: ::core::option::Option<Box<Node>>, - - pub using_clause: Vec<Node>, - - pub quals: ::core::option::Option<Box<Node>>, - - pub alias: ::core::option::Option<Alias>, - - pub rtindex: i32, -} -#[derive(Clone, PartialEq)] -pub struct FromExpr { - pub fromlist: Vec<Node>, - - pub quals: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct OnConflictExpr { - pub action: i32, - - pub arbiter_elems: Vec<Node>, - - pub arbiter_where: ::core::option::Option<Box<Node>>, - - pub constraint: u32, - - pub on_conflict_set: Vec<Node>, - - pub on_conflict_where: ::core::option::Option<Box<Node>>, - - pub excl_rel_index: i32, - - pub excl_rel_tlist: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct IntoClause { - pub rel: ::core::option::Option<RangeVar>, - - pub col_names: Vec<Node>, - - pub access_method: String, - - pub options: Vec<Node>, - - pub on_commit: i32, - - pub table_space_name: String, - - pub view_query: ::core::option::Option<Box<Node>>, - - pub skip_data: bool, -} -#[derive(Clone, PartialEq)] -pub struct RawStmt { - pub stmt: ::core::option::Option<Box<Node>>, - - pub stmt_location: i32, - - pub stmt_len: i32, -} -#[derive(Clone, PartialEq)] -pub struct Query { - pub command_type: i32, - - pub query_source: i32, - - pub can_set_tag: bool, - - pub utility_stmt: ::core::option::Option<Box<Node>>, - - pub result_relation: i32, - - pub has_aggs: bool, - - pub has_window_funcs: bool, - - pub has_target_srfs: bool, - - pub has_sub_links: bool, - - pub has_distinct_on: bool, - - pub has_recursive: bool, - - pub has_modifying_cte: bool, - - pub has_for_update: bool, - - pub has_row_security: bool, - - pub cte_list: Vec<Node>, - - pub rtable: Vec<Node>, - - pub jointree: ::core::option::Option<Box<FromExpr>>, - - pub target_list: Vec<Node>, - - pub r#override: i32, - - pub on_conflict: ::core::option::Option<Box<OnConflictExpr>>, - - pub returning_list: Vec<Node>, - - pub group_clause: Vec<Node>, - - pub grouping_sets: Vec<Node>, - - pub having_qual: ::core::option::Option<Box<Node>>, - - pub window_clause: Vec<Node>, - - pub distinct_clause: Vec<Node>, - - pub sort_clause: Vec<Node>, - - pub limit_offset: ::core::option::Option<Box<Node>>, - - pub limit_count: ::core::option::Option<Box<Node>>, - - pub limit_option: i32, - - pub row_marks: Vec<Node>, - - pub set_operations: ::core::option::Option<Box<Node>>, - - pub constraint_deps: Vec<Node>, - - pub with_check_options: Vec<Node>, - - pub stmt_location: i32, - - pub stmt_len: i32, -} -#[derive(Clone, PartialEq)] -pub struct InsertStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub cols: Vec<Node>, - - pub select_stmt: ::core::option::Option<Box<Node>>, - - pub on_conflict_clause: ::core::option::Option<Box<OnConflictClause>>, - - pub returning_list: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, - - pub r#override: i32, -} -#[derive(Clone, PartialEq)] -pub struct DeleteStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub using_clause: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub returning_list: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, -} -#[derive(Clone, PartialEq)] -pub struct UpdateStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub target_list: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub from_clause: Vec<Node>, - - pub returning_list: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, -} -#[derive(Clone, PartialEq)] -pub struct SelectStmt { - pub distinct_clause: Vec<Node>, - - pub into_clause: ::core::option::Option<Box<IntoClause>>, - - pub target_list: Vec<Node>, - - pub from_clause: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub group_clause: Vec<Node>, - - pub having_clause: ::core::option::Option<Box<Node>>, - - pub window_clause: Vec<Node>, - - pub values_lists: Vec<Node>, - - pub sort_clause: Vec<Node>, - - pub limit_offset: ::core::option::Option<Box<Node>>, - - pub limit_count: ::core::option::Option<Box<Node>>, - - pub limit_option: i32, - - pub locking_clause: Vec<Node>, - - pub with_clause: ::core::option::Option<WithClause>, - - pub op: i32, - - pub all: bool, - - pub larg: ::core::option::Option<Box<SelectStmt>>, - - pub rarg: ::core::option::Option<Box<SelectStmt>>, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub cmds: Vec<Node>, - - pub relkind: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableCmd { - pub subtype: i32, - - pub name: String, - - pub num: i32, - - pub newowner: ::core::option::Option<RoleSpec>, - - pub def: ::core::option::Option<Box<Node>>, - - pub behavior: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterDomainStmt { - pub subtype: String, - - pub type_name: Vec<Node>, - - pub name: String, - - pub def: ::core::option::Option<Box<Node>>, - - pub behavior: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct SetOperationStmt { - pub op: i32, - - pub all: bool, - - pub larg: ::core::option::Option<Box<Node>>, - - pub rarg: ::core::option::Option<Box<Node>>, - - pub col_types: Vec<Node>, - - pub col_typmods: Vec<Node>, - - pub col_collations: Vec<Node>, - - pub group_clauses: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct GrantStmt { - pub is_grant: bool, - - pub targtype: i32, - - pub objtype: i32, - - pub objects: Vec<Node>, - - pub privileges: Vec<Node>, - - pub grantees: Vec<Node>, - - pub grant_option: bool, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct GrantRoleStmt { - pub granted_roles: Vec<Node>, - - pub grantee_roles: Vec<Node>, - - pub is_grant: bool, - - pub admin_opt: bool, - - pub grantor: ::core::option::Option<RoleSpec>, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct AlterDefaultPrivilegesStmt { - pub options: Vec<Node>, - - pub action: ::core::option::Option<GrantStmt>, -} -#[derive(Clone, PartialEq)] -pub struct ClosePortalStmt { - pub portalname: String, -} -#[derive(Clone, PartialEq)] -pub struct ClusterStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub indexname: String, - - pub options: i32, -} -#[derive(Clone, PartialEq)] -pub struct CopyStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub query: ::core::option::Option<Box<Node>>, - - pub attlist: Vec<Node>, - - pub is_from: bool, - - pub is_program: bool, - - pub filename: String, - - pub options: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub table_elts: Vec<Node>, - - pub inh_relations: Vec<Node>, - - pub partbound: ::core::option::Option<PartitionBoundSpec>, - - pub partspec: ::core::option::Option<PartitionSpec>, - - pub of_typename: ::core::option::Option<TypeName>, - - pub constraints: Vec<Node>, - - pub options: Vec<Node>, - - pub oncommit: i32, - - pub tablespacename: String, - - pub access_method: String, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct DefineStmt { - pub kind: i32, - - pub oldstyle: bool, - - pub defnames: Vec<Node>, - - pub args: Vec<Node>, - - pub definition: Vec<Node>, - - pub if_not_exists: bool, - - pub replace: bool, -} -#[derive(Clone, PartialEq)] -pub struct DropStmt { - pub objects: Vec<Node>, - - pub remove_type: i32, - - pub behavior: i32, - - pub missing_ok: bool, - - pub concurrent: bool, -} -#[derive(Clone, PartialEq)] -pub struct TruncateStmt { - pub relations: Vec<Node>, - - pub restart_seqs: bool, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct CommentStmt { - pub objtype: i32, - - pub object: ::core::option::Option<Box<Node>>, - - pub comment: String, -} -#[derive(Clone, PartialEq)] -pub struct FetchStmt { - pub direction: i32, - - pub how_many: i64, - - pub portalname: String, - - pub ismove: bool, -} -#[derive(Clone, PartialEq)] -pub struct IndexStmt { - pub idxname: String, - - pub relation: ::core::option::Option<RangeVar>, - - pub access_method: String, - - pub table_space: String, - - pub index_params: Vec<Node>, - - pub index_including_params: Vec<Node>, - - pub options: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub exclude_op_names: Vec<Node>, - - pub idxcomment: String, - - pub index_oid: u32, - - pub old_node: u32, - - pub old_create_subid: u32, - - pub old_first_relfilenode_subid: u32, - - pub unique: bool, - - pub primary: bool, - - pub isconstraint: bool, - - pub deferrable: bool, - - pub initdeferred: bool, - - pub transformed: bool, - - pub concurrent: bool, - - pub if_not_exists: bool, - - pub reset_default_tblspc: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateFunctionStmt { - pub is_procedure: bool, - - pub replace: bool, - - pub funcname: Vec<Node>, - - pub parameters: Vec<Node>, - - pub return_type: ::core::option::Option<TypeName>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterFunctionStmt { - pub objtype: i32, - - pub func: ::core::option::Option<ObjectWithArgs>, - - pub actions: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DoStmt { - pub args: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RenameStmt { - pub rename_type: i32, - - pub relation_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub subname: String, - - pub newname: String, - - pub behavior: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct RuleStmt { - pub relation: ::core::option::Option<RangeVar>, - - pub rulename: String, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub event: i32, - - pub instead: bool, - - pub actions: Vec<Node>, - - pub replace: bool, -} -#[derive(Clone, PartialEq)] -pub struct NotifyStmt { - pub conditionname: String, - - pub payload: String, -} -#[derive(Clone, PartialEq)] -pub struct ListenStmt { - pub conditionname: String, -} -#[derive(Clone, PartialEq)] -pub struct UnlistenStmt { - pub conditionname: String, -} -#[derive(Clone, PartialEq)] -pub struct TransactionStmt { - pub kind: i32, - - pub options: Vec<Node>, - - pub savepoint_name: String, - - pub gid: String, - - pub chain: bool, -} -#[derive(Clone, PartialEq)] -pub struct ViewStmt { - pub view: ::core::option::Option<RangeVar>, - - pub aliases: Vec<Node>, - - pub query: ::core::option::Option<Box<Node>>, - - pub replace: bool, - - pub options: Vec<Node>, - - pub with_check_option: i32, -} -#[derive(Clone, PartialEq)] -pub struct LoadStmt { - pub filename: String, -} -#[derive(Clone, PartialEq)] -pub struct CreateDomainStmt { - pub domainname: Vec<Node>, - - pub type_name: ::core::option::Option<TypeName>, - - pub coll_clause: ::core::option::Option<Box<CollateClause>>, - - pub constraints: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreatedbStmt { - pub dbname: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropdbStmt { - pub dbname: String, - - pub missing_ok: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct VacuumStmt { - pub options: Vec<Node>, - - pub rels: Vec<Node>, - - pub is_vacuumcmd: bool, -} -#[derive(Clone, PartialEq)] -pub struct ExplainStmt { - pub query: ::core::option::Option<Box<Node>>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateTableAsStmt { - pub query: ::core::option::Option<Box<Node>>, - - pub into: ::core::option::Option<Box<IntoClause>>, - - pub relkind: i32, - - pub is_select_into: bool, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateSeqStmt { - pub sequence: ::core::option::Option<RangeVar>, - - pub options: Vec<Node>, - - pub owner_id: u32, - - pub for_identity: bool, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterSeqStmt { - pub sequence: ::core::option::Option<RangeVar>, - - pub options: Vec<Node>, - - pub for_identity: bool, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct VariableSetStmt { - pub kind: i32, - - pub name: String, - - pub args: Vec<Node>, - - pub is_local: bool, -} -#[derive(Clone, PartialEq)] -pub struct VariableShowStmt { - pub name: String, -} -#[derive(Clone, PartialEq)] -pub struct DiscardStmt { - pub target: i32, -} -#[derive(Clone, PartialEq)] -pub struct CreateTrigStmt { - pub trigname: String, - - pub relation: ::core::option::Option<RangeVar>, - - pub funcname: Vec<Node>, - - pub args: Vec<Node>, - - pub row: bool, - - pub timing: i32, - - pub events: i32, - - pub columns: Vec<Node>, - - pub when_clause: ::core::option::Option<Box<Node>>, - - pub isconstraint: bool, - - pub transition_rels: Vec<Node>, - - pub deferrable: bool, - - pub initdeferred: bool, - - pub constrrel: ::core::option::Option<RangeVar>, -} -#[derive(Clone, PartialEq)] -pub struct CreatePLangStmt { - pub replace: bool, - - pub plname: String, - - pub plhandler: Vec<Node>, - - pub plinline: Vec<Node>, - - pub plvalidator: Vec<Node>, - - pub pltrusted: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateRoleStmt { - pub stmt_type: i32, - - pub role: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterRoleStmt { - pub role: ::core::option::Option<RoleSpec>, - - pub options: Vec<Node>, - - pub action: i32, -} -#[derive(Clone, PartialEq)] -pub struct DropRoleStmt { - pub roles: Vec<Node>, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct LockStmt { - pub relations: Vec<Node>, - - pub mode: i32, - - pub nowait: bool, -} -#[derive(Clone, PartialEq)] -pub struct ConstraintsSetStmt { - pub constraints: Vec<Node>, - - pub deferred: bool, -} -#[derive(Clone, PartialEq)] -pub struct ReindexStmt { - pub kind: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub name: String, - - pub options: i32, - - pub concurrent: bool, -} -#[derive(Clone, PartialEq)] -pub struct CheckPointStmt {} -#[derive(Clone, PartialEq)] -pub struct CreateSchemaStmt { - pub schemaname: String, - - pub authrole: ::core::option::Option<RoleSpec>, - - pub schema_elts: Vec<Node>, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterDatabaseStmt { - pub dbname: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterDatabaseSetStmt { - pub dbname: String, - - pub setstmt: ::core::option::Option<VariableSetStmt>, -} -#[derive(Clone, PartialEq)] -pub struct AlterRoleSetStmt { - pub role: ::core::option::Option<RoleSpec>, - - pub database: String, - - pub setstmt: ::core::option::Option<VariableSetStmt>, -} -#[derive(Clone, PartialEq)] -pub struct CreateConversionStmt { - pub conversion_name: Vec<Node>, - - pub for_encoding_name: String, - - pub to_encoding_name: String, - - pub func_name: Vec<Node>, - - pub def: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateCastStmt { - pub sourcetype: ::core::option::Option<TypeName>, - - pub targettype: ::core::option::Option<TypeName>, - - pub func: ::core::option::Option<ObjectWithArgs>, - - pub context: i32, - - pub inout: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateOpClassStmt { - pub opclassname: Vec<Node>, - - pub opfamilyname: Vec<Node>, - - pub amname: String, - - pub datatype: ::core::option::Option<TypeName>, - - pub items: Vec<Node>, - - pub is_default: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateOpFamilyStmt { - pub opfamilyname: Vec<Node>, - - pub amname: String, -} -#[derive(Clone, PartialEq)] -pub struct AlterOpFamilyStmt { - pub opfamilyname: Vec<Node>, - - pub amname: String, - - pub is_drop: bool, - - pub items: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct PrepareStmt { - pub name: String, - - pub argtypes: Vec<Node>, - - pub query: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct ExecuteStmt { - pub name: String, - - pub params: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DeallocateStmt { - pub name: String, -} -#[derive(Clone, PartialEq)] -pub struct DeclareCursorStmt { - pub portalname: String, - - pub options: i32, - - pub query: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateTableSpaceStmt { - pub tablespacename: String, - - pub owner: ::core::option::Option<RoleSpec>, - - pub location: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropTableSpaceStmt { - pub tablespacename: String, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterObjectDependsStmt { - pub object_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub extname: ::core::option::Option<Box<Node>>, - - pub remove: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterObjectSchemaStmt { - pub object_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub newschema: String, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterOwnerStmt { - pub object_type: i32, - - pub relation: ::core::option::Option<RangeVar>, - - pub object: ::core::option::Option<Box<Node>>, - - pub newowner: ::core::option::Option<RoleSpec>, -} -#[derive(Clone, PartialEq)] -pub struct AlterOperatorStmt { - pub opername: ::core::option::Option<ObjectWithArgs>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterTypeStmt { - pub type_name: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropOwnedStmt { - pub roles: Vec<Node>, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct ReassignOwnedStmt { - pub roles: Vec<Node>, - - pub newrole: ::core::option::Option<RoleSpec>, -} -#[derive(Clone, PartialEq)] -pub struct CompositeTypeStmt { - pub typevar: ::core::option::Option<RangeVar>, - - pub coldeflist: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateEnumStmt { - pub type_name: Vec<Node>, - - pub vals: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateRangeStmt { - pub type_name: Vec<Node>, - - pub params: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterEnumStmt { - pub type_name: Vec<Node>, - - pub old_val: String, - - pub new_val: String, - - pub new_val_neighbor: String, - - pub new_val_is_after: bool, - - pub skip_if_new_val_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTsDictionaryStmt { - pub dictname: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterTsConfigurationStmt { - pub kind: i32, - - pub cfgname: Vec<Node>, - - pub tokentype: Vec<Node>, - - pub dicts: Vec<Node>, - - pub r#override: bool, - - pub replace: bool, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateFdwStmt { - pub fdwname: String, - - pub func_options: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterFdwStmt { - pub fdwname: String, - - pub func_options: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateForeignServerStmt { - pub servername: String, - - pub servertype: String, - - pub version: String, - - pub fdwname: String, - - pub if_not_exists: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterForeignServerStmt { - pub servername: String, - - pub version: String, - - pub options: Vec<Node>, - - pub has_version: bool, -} -#[derive(Clone, PartialEq)] -pub struct CreateUserMappingStmt { - pub user: ::core::option::Option<RoleSpec>, - - pub servername: String, - - pub if_not_exists: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterUserMappingStmt { - pub user: ::core::option::Option<RoleSpec>, - - pub servername: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropUserMappingStmt { - pub user: ::core::option::Option<RoleSpec>, - - pub servername: String, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableSpaceOptionsStmt { - pub tablespacename: String, - - pub options: Vec<Node>, - - pub is_reset: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterTableMoveAllStmt { - pub orig_tablespacename: String, - - pub objtype: i32, - - pub roles: Vec<Node>, - - pub new_tablespacename: String, - - pub nowait: bool, -} -#[derive(Clone, PartialEq)] -pub struct SecLabelStmt { - pub objtype: i32, - - pub object: ::core::option::Option<Box<Node>>, - - pub provider: String, - - pub label: String, -} -#[derive(Clone, PartialEq)] -pub struct CreateForeignTableStmt { - pub base_stmt: ::core::option::Option<CreateStmt>, - - pub servername: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct ImportForeignSchemaStmt { - pub server_name: String, - - pub remote_schema: String, - - pub local_schema: String, - - pub list_type: i32, - - pub table_list: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateExtensionStmt { - pub extname: String, - - pub if_not_exists: bool, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterExtensionStmt { - pub extname: String, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterExtensionContentsStmt { - pub extname: String, - - pub action: i32, - - pub objtype: i32, - - pub object: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateEventTrigStmt { - pub trigname: String, - - pub eventname: String, - - pub whenclause: Vec<Node>, - - pub funcname: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterEventTrigStmt { - pub trigname: String, - - pub tgenabled: String, -} -#[derive(Clone, PartialEq)] -pub struct RefreshMatViewStmt { - pub concurrent: bool, - - pub skip_data: bool, - - pub relation: ::core::option::Option<RangeVar>, -} -#[derive(Clone, PartialEq)] -pub struct ReplicaIdentityStmt { - pub identity_type: String, - - pub name: String, -} -#[derive(Clone, PartialEq)] -pub struct AlterSystemStmt { - pub setstmt: ::core::option::Option<VariableSetStmt>, -} -#[derive(Clone, PartialEq)] -pub struct CreatePolicyStmt { - pub policy_name: String, - - pub table: ::core::option::Option<RangeVar>, - - pub cmd_name: String, - - pub permissive: bool, - - pub roles: Vec<Node>, - - pub qual: ::core::option::Option<Box<Node>>, - - pub with_check: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct AlterPolicyStmt { - pub policy_name: String, - - pub table: ::core::option::Option<RangeVar>, - - pub roles: Vec<Node>, - - pub qual: ::core::option::Option<Box<Node>>, - - pub with_check: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct CreateTransformStmt { - pub replace: bool, - - pub type_name: ::core::option::Option<TypeName>, - - pub lang: String, - - pub fromsql: ::core::option::Option<ObjectWithArgs>, - - pub tosql: ::core::option::Option<ObjectWithArgs>, -} -#[derive(Clone, PartialEq)] -pub struct CreateAmStmt { - pub amname: String, - - pub handler_name: Vec<Node>, - - pub amtype: String, -} -#[derive(Clone, PartialEq)] -pub struct CreatePublicationStmt { - pub pubname: String, - - pub options: Vec<Node>, - - pub tables: Vec<Node>, - - pub for_all_tables: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterPublicationStmt { - pub pubname: String, - - pub options: Vec<Node>, - - pub tables: Vec<Node>, - - pub for_all_tables: bool, - - pub table_action: i32, -} -#[derive(Clone, PartialEq)] -pub struct CreateSubscriptionStmt { - pub subname: String, - - pub conninfo: String, - - pub publication: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AlterSubscriptionStmt { - pub kind: i32, - - pub subname: String, - - pub conninfo: String, - - pub publication: Vec<Node>, - - pub options: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct DropSubscriptionStmt { - pub subname: String, - - pub missing_ok: bool, - - pub behavior: i32, -} -#[derive(Clone, PartialEq)] -pub struct CreateStatsStmt { - pub defnames: Vec<Node>, - - pub stat_types: Vec<Node>, - - pub exprs: Vec<Node>, - - pub relations: Vec<Node>, - - pub stxcomment: String, - - pub if_not_exists: bool, -} -#[derive(Clone, PartialEq)] -pub struct AlterCollationStmt { - pub collname: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CallStmt { - pub funccall: ::core::option::Option<Box<FuncCall>>, - - pub funcexpr: ::core::option::Option<Box<FuncExpr>>, -} -#[derive(Clone, PartialEq)] -pub struct AlterStatsStmt { - pub defnames: Vec<Node>, - - pub stxstattarget: i32, - - pub missing_ok: bool, -} -#[derive(Clone, PartialEq)] -pub struct AExpr { - pub kind: i32, - - pub name: Vec<Node>, - - pub lexpr: ::core::option::Option<Box<Node>>, - - pub rexpr: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ColumnRef { - pub fields: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ParamRef { - pub number: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct AConst { - pub val: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct FuncCall { - pub funcname: Vec<Node>, - - pub args: Vec<Node>, - - pub agg_order: Vec<Node>, - - pub agg_filter: ::core::option::Option<Box<Node>>, - - pub agg_within_group: bool, - - pub agg_star: bool, - - pub agg_distinct: bool, - - pub func_variadic: bool, - - pub over: ::core::option::Option<Box<WindowDef>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct AStar {} -#[derive(Clone, PartialEq)] -pub struct AIndices { - pub is_slice: bool, - - pub lidx: ::core::option::Option<Box<Node>>, - - pub uidx: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct AIndirection { - pub arg: ::core::option::Option<Box<Node>>, - - pub indirection: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct AArrayExpr { - pub elements: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ResTarget { - pub name: String, - - pub indirection: Vec<Node>, - - pub val: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct MultiAssignRef { - pub source: ::core::option::Option<Box<Node>>, - - pub colno: i32, - - pub ncolumns: i32, -} -#[derive(Clone, PartialEq)] -pub struct TypeCast { - pub arg: ::core::option::Option<Box<Node>>, - - pub type_name: ::core::option::Option<TypeName>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CollateClause { - pub arg: ::core::option::Option<Box<Node>>, - - pub collname: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct SortBy { - pub node: ::core::option::Option<Box<Node>>, - - pub sortby_dir: i32, - - pub sortby_nulls: i32, - - pub use_op: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WindowDef { - pub name: String, - - pub refname: String, - - pub partition_clause: Vec<Node>, - - pub order_clause: Vec<Node>, - - pub frame_options: i32, - - pub start_offset: ::core::option::Option<Box<Node>>, - - pub end_offset: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeSubselect { - pub lateral: bool, - - pub subquery: ::core::option::Option<Box<Node>>, - - pub alias: ::core::option::Option<Alias>, -} -#[derive(Clone, PartialEq)] -pub struct RangeFunction { - pub lateral: bool, - - pub ordinality: bool, - - pub is_rowsfrom: bool, - - pub functions: Vec<Node>, - - pub alias: ::core::option::Option<Alias>, - - pub coldeflist: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RangeTableSample { - pub relation: ::core::option::Option<Box<Node>>, - - pub method: Vec<Node>, - - pub args: Vec<Node>, - - pub repeatable: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeTableFunc { - pub lateral: bool, - - pub docexpr: ::core::option::Option<Box<Node>>, - - pub rowexpr: ::core::option::Option<Box<Node>>, - - pub namespaces: Vec<Node>, - - pub columns: Vec<Node>, - - pub alias: ::core::option::Option<Alias>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeTableFuncCol { - pub colname: String, - - pub type_name: ::core::option::Option<TypeName>, - - pub for_ordinality: bool, - - pub is_not_null: bool, - - pub colexpr: ::core::option::Option<Box<Node>>, - - pub coldefexpr: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct TypeName { - pub names: Vec<Node>, - - pub type_oid: u32, - - pub setof: bool, - - pub pct_type: bool, - - pub typmods: Vec<Node>, - - pub typemod: i32, - - pub array_bounds: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct ColumnDef { - pub colname: String, - - pub type_name: ::core::option::Option<TypeName>, - - pub inhcount: i32, - - pub is_local: bool, - - pub is_not_null: bool, - - pub is_from_type: bool, - - pub storage: String, - - pub raw_default: ::core::option::Option<Box<Node>>, - - pub cooked_default: ::core::option::Option<Box<Node>>, - - pub identity: String, - - pub identity_sequence: ::core::option::Option<RangeVar>, - - pub generated: String, - - pub coll_clause: ::core::option::Option<Box<CollateClause>>, - - pub coll_oid: u32, - - pub constraints: Vec<Node>, - - pub fdwoptions: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct IndexElem { - pub name: String, - - pub expr: ::core::option::Option<Box<Node>>, - - pub indexcolname: String, - - pub collation: Vec<Node>, - - pub opclass: Vec<Node>, - - pub opclassopts: Vec<Node>, - - pub ordering: i32, - - pub nulls_ordering: i32, -} -#[derive(Clone, PartialEq)] -pub struct Constraint { - pub contype: i32, - - pub conname: String, - - pub deferrable: bool, - - pub initdeferred: bool, - - pub location: i32, - - pub is_no_inherit: bool, - - pub raw_expr: ::core::option::Option<Box<Node>>, - - pub cooked_expr: String, - - pub generated_when: String, - - pub keys: Vec<Node>, - - pub including: Vec<Node>, - - pub exclusions: Vec<Node>, - - pub options: Vec<Node>, - - pub indexname: String, - - pub indexspace: String, - - pub reset_default_tblspc: bool, - - pub access_method: String, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub pktable: ::core::option::Option<RangeVar>, - - pub fk_attrs: Vec<Node>, - - pub pk_attrs: Vec<Node>, - - pub fk_matchtype: String, - - pub fk_upd_action: String, - - pub fk_del_action: String, - - pub old_conpfeqop: Vec<Node>, - - pub old_pktable_oid: u32, - - pub skip_validation: bool, - - pub initially_valid: bool, -} -#[derive(Clone, PartialEq)] -pub struct DefElem { - pub defnamespace: String, - - pub defname: String, - - pub arg: ::core::option::Option<Box<Node>>, - - pub defaction: i32, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct RangeTblEntry { - pub rtekind: i32, - - pub relid: u32, - - pub relkind: String, - - pub rellockmode: i32, - - pub tablesample: ::core::option::Option<Box<TableSampleClause>>, - - pub subquery: ::core::option::Option<Box<Query>>, - - pub security_barrier: bool, - - pub jointype: i32, - - pub joinmergedcols: i32, - - pub joinaliasvars: Vec<Node>, - - pub joinleftcols: Vec<Node>, - - pub joinrightcols: Vec<Node>, - - pub functions: Vec<Node>, - - pub funcordinality: bool, - - pub tablefunc: ::core::option::Option<Box<TableFunc>>, - - pub values_lists: Vec<Node>, - - pub ctename: String, - - pub ctelevelsup: u32, - - pub self_reference: bool, - - pub coltypes: Vec<Node>, - - pub coltypmods: Vec<Node>, - - pub colcollations: Vec<Node>, - - pub enrname: String, - - pub enrtuples: f64, - - pub alias: ::core::option::Option<Alias>, - - pub eref: ::core::option::Option<Alias>, - - pub lateral: bool, - - pub inh: bool, - - pub in_from_cl: bool, - - pub required_perms: u32, - - pub check_as_user: u32, - - pub selected_cols: Vec<u64>, - - pub inserted_cols: Vec<u64>, - - pub updated_cols: Vec<u64>, - - pub extra_updated_cols: Vec<u64>, - - pub security_quals: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RangeTblFunction { - pub funcexpr: ::core::option::Option<Box<Node>>, - - pub funccolcount: i32, - - pub funccolnames: Vec<Node>, - - pub funccoltypes: Vec<Node>, - - pub funccoltypmods: Vec<Node>, - - pub funccolcollations: Vec<Node>, - - pub funcparams: Vec<u64>, -} -#[derive(Clone, PartialEq)] -pub struct TableSampleClause { - pub tsmhandler: u32, - - pub args: Vec<Node>, - - pub repeatable: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct WithCheckOption { - pub kind: i32, - - pub relname: String, - - pub polname: String, - - pub qual: ::core::option::Option<Box<Node>>, - - pub cascaded: bool, -} -#[derive(Clone, PartialEq)] -pub struct SortGroupClause { - pub tle_sort_group_ref: u32, - - pub eqop: u32, - - pub sortop: u32, - - pub nulls_first: bool, - - pub hashable: bool, -} -#[derive(Clone, PartialEq)] -pub struct GroupingSet { - pub kind: i32, - - pub content: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WindowClause { - pub name: String, - - pub refname: String, - - pub partition_clause: Vec<Node>, - - pub order_clause: Vec<Node>, - - pub frame_options: i32, - - pub start_offset: ::core::option::Option<Box<Node>>, - - pub end_offset: ::core::option::Option<Box<Node>>, - - pub start_in_range_func: u32, - - pub end_in_range_func: u32, - - pub in_range_coll: u32, - - pub in_range_asc: bool, - - pub in_range_nulls_first: bool, - - pub winref: u32, - - pub copied_order: bool, -} -#[derive(Clone, PartialEq)] -pub struct ObjectWithArgs { - pub objname: Vec<Node>, - - pub objargs: Vec<Node>, - - pub args_unspecified: bool, -} -#[derive(Clone, PartialEq)] -pub struct AccessPriv { - pub priv_name: String, - - pub cols: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct CreateOpClassItem { - pub itemtype: i32, - - pub name: ::core::option::Option<ObjectWithArgs>, - - pub number: i32, - - pub order_family: Vec<Node>, - - pub class_args: Vec<Node>, - - pub storedtype: ::core::option::Option<TypeName>, -} -#[derive(Clone, PartialEq)] -pub struct TableLikeClause { - pub relation: ::core::option::Option<RangeVar>, - - pub options: u32, - - pub relation_oid: u32, -} -#[derive(Clone, PartialEq)] -pub struct FunctionParameter { - pub name: String, - - pub arg_type: ::core::option::Option<TypeName>, - - pub mode: i32, - - pub defexpr: ::core::option::Option<Box<Node>>, -} -#[derive(Clone, PartialEq)] -pub struct LockingClause { - pub locked_rels: Vec<Node>, - - pub strength: i32, - - pub wait_policy: i32, -} -#[derive(Clone, PartialEq)] -pub struct RowMarkClause { - pub rti: u32, - - pub strength: i32, - - pub wait_policy: i32, - - pub pushed_down: bool, -} -#[derive(Clone, PartialEq)] -pub struct XmlSerialize { - pub xmloption: i32, - - pub expr: ::core::option::Option<Box<Node>>, - - pub type_name: ::core::option::Option<TypeName>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct WithClause { - pub ctes: Vec<Node>, - - pub recursive: bool, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct InferClause { - pub index_elems: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub conname: String, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct OnConflictClause { - pub action: i32, - - pub infer: ::core::option::Option<Box<InferClause>>, - - pub target_list: Vec<Node>, - - pub where_clause: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct CommonTableExpr { - pub ctename: String, - - pub aliascolnames: Vec<Node>, - - pub ctematerialized: i32, - - pub ctequery: ::core::option::Option<Box<Node>>, - - pub location: i32, - - pub cterecursive: bool, - - pub cterefcount: i32, - - pub ctecolnames: Vec<Node>, - - pub ctecoltypes: Vec<Node>, - - pub ctecoltypmods: Vec<Node>, - - pub ctecolcollations: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct RoleSpec { - pub roletype: i32, - - pub rolename: String, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct TriggerTransition { - pub name: String, - - pub is_new: bool, - - pub is_table: bool, -} -#[derive(Clone, PartialEq)] -pub struct PartitionElem { - pub name: String, - - pub expr: ::core::option::Option<Box<Node>>, - - pub collation: Vec<Node>, - - pub opclass: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionSpec { - pub strategy: String, - - pub part_params: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionBoundSpec { - pub strategy: String, - - pub is_default: bool, - - pub modulus: i32, - - pub remainder: i32, - - pub listdatums: Vec<Node>, - - pub lowerdatums: Vec<Node>, - - pub upperdatums: Vec<Node>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionRangeDatum { - pub kind: i32, - - pub value: ::core::option::Option<Box<Node>>, - - pub location: i32, -} -#[derive(Clone, PartialEq)] -pub struct PartitionCmd { - pub name: ::core::option::Option<RangeVar>, - - pub bound: ::core::option::Option<PartitionBoundSpec>, -} -#[derive(Clone, PartialEq)] -pub struct VacuumRelation { - pub relation: ::core::option::Option<RangeVar>, - - pub oid: u32, - - pub va_cols: Vec<Node>, -} -#[derive(Clone, PartialEq)] -pub struct InlineCodeBlock { - pub source_text: String, - - pub lang_oid: u32, - - pub lang_is_trusted: bool, - - pub atomic: bool, -} -#[derive(Clone, PartialEq)] -pub struct CallContext { - pub atomic: bool, -} -#[derive(Clone, PartialEq)] -pub struct ScanToken { - pub start: i32, - - pub end: i32, - - pub token: i32, - - pub keyword_kind: i32, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum OverridingKind { - Undefined = 0, - OverridingNotSet = 1, - OverridingUserValue = 2, - OverridingSystemValue = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum QuerySource { - Undefined = 0, - QsrcOriginal = 1, - QsrcParser = 2, - QsrcInsteadRule = 3, - QsrcQualInsteadRule = 4, - QsrcNonInsteadRule = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SortByDir { - Undefined = 0, - SortbyDefault = 1, - SortbyAsc = 2, - SortbyDesc = 3, - SortbyUsing = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SortByNulls { - Undefined = 0, - SortbyNullsDefault = 1, - SortbyNullsFirst = 2, - SortbyNullsLast = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AExprKind { - Undefined = 0, - AexprOp = 1, - AexprOpAny = 2, - AexprOpAll = 3, - AexprDistinct = 4, - AexprNotDistinct = 5, - AexprNullif = 6, - AexprOf = 7, - AexprIn = 8, - AexprLike = 9, - AexprIlike = 10, - AexprSimilar = 11, - AexprBetween = 12, - AexprNotBetween = 13, - AexprBetweenSym = 14, - AexprNotBetweenSym = 15, - AexprParen = 16, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RoleSpecType { - Undefined = 0, - RolespecCstring = 1, - RolespecCurrentUser = 2, - RolespecSessionUser = 3, - RolespecPublic = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum TableLikeOption { - Undefined = 0, - CreateTableLikeComments = 1, - CreateTableLikeConstraints = 2, - CreateTableLikeDefaults = 3, - CreateTableLikeGenerated = 4, - CreateTableLikeIdentity = 5, - CreateTableLikeIndexes = 6, - CreateTableLikeStatistics = 7, - CreateTableLikeStorage = 8, - CreateTableLikeAll = 9, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum DefElemAction { - Undefined = 0, - DefelemUnspec = 1, - DefelemSet = 2, - DefelemAdd = 3, - DefelemDrop = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum PartitionRangeDatumKind { - Undefined = 0, - PartitionRangeDatumMinvalue = 1, - PartitionRangeDatumValue = 2, - PartitionRangeDatumMaxvalue = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RteKind { - RtekindUndefined = 0, - RteRelation = 1, - RteSubquery = 2, - RteJoin = 3, - RteFunction = 4, - RteTablefunc = 5, - RteValues = 6, - RteCte = 7, - RteNamedtuplestore = 8, - RteResult = 9, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum WcoKind { - WcokindUndefined = 0, - WcoViewCheck = 1, - WcoRlsInsertCheck = 2, - WcoRlsUpdateCheck = 3, - WcoRlsConflictCheck = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum GroupingSetKind { - Undefined = 0, - GroupingSetEmpty = 1, - GroupingSetSimple = 2, - GroupingSetRollup = 3, - GroupingSetCube = 4, - GroupingSetSets = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CteMaterialize { - CtematerializeUndefined = 0, - Default = 1, - Always = 2, - Never = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SetOperation { - Undefined = 0, - SetopNone = 1, - SetopUnion = 2, - SetopIntersect = 3, - SetopExcept = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ObjectType { - Undefined = 0, - ObjectAccessMethod = 1, - ObjectAggregate = 2, - ObjectAmop = 3, - ObjectAmproc = 4, - ObjectAttribute = 5, - ObjectCast = 6, - ObjectColumn = 7, - ObjectCollation = 8, - ObjectConversion = 9, - ObjectDatabase = 10, - ObjectDefault = 11, - ObjectDefacl = 12, - ObjectDomain = 13, - ObjectDomconstraint = 14, - ObjectEventTrigger = 15, - ObjectExtension = 16, - ObjectFdw = 17, - ObjectForeignServer = 18, - ObjectForeignTable = 19, - ObjectFunction = 20, - ObjectIndex = 21, - ObjectLanguage = 22, - ObjectLargeobject = 23, - ObjectMatview = 24, - ObjectOpclass = 25, - ObjectOperator = 26, - ObjectOpfamily = 27, - ObjectPolicy = 28, - ObjectProcedure = 29, - ObjectPublication = 30, - ObjectPublicationRel = 31, - ObjectRole = 32, - ObjectRoutine = 33, - ObjectRule = 34, - ObjectSchema = 35, - ObjectSequence = 36, - ObjectSubscription = 37, - ObjectStatisticExt = 38, - ObjectTabconstraint = 39, - ObjectTable = 40, - ObjectTablespace = 41, - ObjectTransform = 42, - ObjectTrigger = 43, - ObjectTsconfiguration = 44, - ObjectTsdictionary = 45, - ObjectTsparser = 46, - ObjectTstemplate = 47, - ObjectType = 48, - ObjectUserMapping = 49, - ObjectView = 50, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum DropBehavior { - Undefined = 0, - DropRestrict = 1, - DropCascade = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AlterTableType { - Undefined = 0, - AtAddColumn = 1, - AtAddColumnRecurse = 2, - AtAddColumnToView = 3, - AtColumnDefault = 4, - AtCookedColumnDefault = 5, - AtDropNotNull = 6, - AtSetNotNull = 7, - AtDropExpression = 8, - AtCheckNotNull = 9, - AtSetStatistics = 10, - AtSetOptions = 11, - AtResetOptions = 12, - AtSetStorage = 13, - AtDropColumn = 14, - AtDropColumnRecurse = 15, - AtAddIndex = 16, - AtReAddIndex = 17, - AtAddConstraint = 18, - AtAddConstraintRecurse = 19, - AtReAddConstraint = 20, - AtReAddDomainConstraint = 21, - AtAlterConstraint = 22, - AtValidateConstraint = 23, - AtValidateConstraintRecurse = 24, - AtAddIndexConstraint = 25, - AtDropConstraint = 26, - AtDropConstraintRecurse = 27, - AtReAddComment = 28, - AtAlterColumnType = 29, - AtAlterColumnGenericOptions = 30, - AtChangeOwner = 31, - AtClusterOn = 32, - AtDropCluster = 33, - AtSetLogged = 34, - AtSetUnLogged = 35, - AtDropOids = 36, - AtSetTableSpace = 37, - AtSetRelOptions = 38, - AtResetRelOptions = 39, - AtReplaceRelOptions = 40, - AtEnableTrig = 41, - AtEnableAlwaysTrig = 42, - AtEnableReplicaTrig = 43, - AtDisableTrig = 44, - AtEnableTrigAll = 45, - AtDisableTrigAll = 46, - AtEnableTrigUser = 47, - AtDisableTrigUser = 48, - AtEnableRule = 49, - AtEnableAlwaysRule = 50, - AtEnableReplicaRule = 51, - AtDisableRule = 52, - AtAddInherit = 53, - AtDropInherit = 54, - AtAddOf = 55, - AtDropOf = 56, - AtReplicaIdentity = 57, - AtEnableRowSecurity = 58, - AtDisableRowSecurity = 59, - AtForceRowSecurity = 60, - AtNoForceRowSecurity = 61, - AtGenericOptions = 62, - AtAttachPartition = 63, - AtDetachPartition = 64, - AtAddIdentity = 65, - AtSetIdentity = 66, - AtDropIdentity = 67, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum GrantTargetType { - Undefined = 0, - AclTargetObject = 1, - AclTargetAllInSchema = 2, - AclTargetDefaults = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum VariableSetKind { - Undefined = 0, - VarSetValue = 1, - VarSetDefault = 2, - VarSetCurrent = 3, - VarSetMulti = 4, - VarReset = 5, - VarResetAll = 6, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ConstrType { - Undefined = 0, - ConstrNull = 1, - ConstrNotnull = 2, - ConstrDefault = 3, - ConstrIdentity = 4, - ConstrGenerated = 5, - ConstrCheck = 6, - ConstrPrimary = 7, - ConstrUnique = 8, - ConstrExclusion = 9, - ConstrForeign = 10, - ConstrAttrDeferrable = 11, - ConstrAttrNotDeferrable = 12, - ConstrAttrDeferred = 13, - ConstrAttrImmediate = 14, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ImportForeignSchemaType { - Undefined = 0, - FdwImportSchemaAll = 1, - FdwImportSchemaLimitTo = 2, - FdwImportSchemaExcept = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RoleStmtType { - Undefined = 0, - RolestmtRole = 1, - RolestmtUser = 2, - RolestmtGroup = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum FetchDirection { - Undefined = 0, - FetchForward = 1, - FetchBackward = 2, - FetchAbsolute = 3, - FetchRelative = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum FunctionParameterMode { - Undefined = 0, - FuncParamIn = 1, - FuncParamOut = 2, - FuncParamInout = 3, - FuncParamVariadic = 4, - FuncParamTable = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum TransactionStmtKind { - Undefined = 0, - TransStmtBegin = 1, - TransStmtStart = 2, - TransStmtCommit = 3, - TransStmtRollback = 4, - TransStmtSavepoint = 5, - TransStmtRelease = 6, - TransStmtRollbackTo = 7, - TransStmtPrepare = 8, - TransStmtCommitPrepared = 9, - TransStmtRollbackPrepared = 10, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ViewCheckOption { - Undefined = 0, - NoCheckOption = 1, - LocalCheckOption = 2, - CascadedCheckOption = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ClusterOption { - Undefined = 0, - CluoptRecheck = 1, - CluoptVerbose = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum DiscardMode { - Undefined = 0, - DiscardAll = 1, - DiscardPlans = 2, - DiscardSequences = 3, - DiscardTemp = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ReindexObjectType { - Undefined = 0, - ReindexObjectIndex = 1, - ReindexObjectTable = 2, - ReindexObjectSchema = 3, - ReindexObjectSystem = 4, - ReindexObjectDatabase = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AlterTsConfigType { - AlterTsconfigTypeUndefined = 0, - AlterTsconfigAddMapping = 1, - AlterTsconfigAlterMappingForToken = 2, - AlterTsconfigReplaceDict = 3, - AlterTsconfigReplaceDictForToken = 4, - AlterTsconfigDropMapping = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AlterSubscriptionType { - Undefined = 0, - AlterSubscriptionOptions = 1, - AlterSubscriptionConnection = 2, - AlterSubscriptionPublication = 3, - AlterSubscriptionRefresh = 4, - AlterSubscriptionEnabled = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum OnCommitAction { - Undefined = 0, - OncommitNoop = 1, - OncommitPreserveRows = 2, - OncommitDeleteRows = 3, - OncommitDrop = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum ParamKind { - Undefined = 0, - ParamExtern = 1, - ParamExec = 2, - ParamSublink = 3, - ParamMultiexpr = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CoercionContext { - Undefined = 0, - CoercionImplicit = 1, - CoercionAssignment = 2, - CoercionExplicit = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CoercionForm { - Undefined = 0, - CoerceExplicitCall = 1, - CoerceExplicitCast = 2, - CoerceImplicitCast = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum BoolExprType { - Undefined = 0, - AndExpr = 1, - OrExpr = 2, - NotExpr = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SubLinkType { - Undefined = 0, - ExistsSublink = 1, - AllSublink = 2, - AnySublink = 3, - RowcompareSublink = 4, - ExprSublink = 5, - MultiexprSublink = 6, - ArraySublink = 7, - CteSublink = 8, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum RowCompareType { - Undefined = 0, - RowcompareLt = 1, - RowcompareLe = 2, - RowcompareEq = 3, - RowcompareGe = 4, - RowcompareGt = 5, - RowcompareNe = 6, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum MinMaxOp { - Undefined = 0, - IsGreatest = 1, - IsLeast = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SqlValueFunctionOp { - SqlvalueFunctionOpUndefined = 0, - SvfopCurrentDate = 1, - SvfopCurrentTime = 2, - SvfopCurrentTimeN = 3, - SvfopCurrentTimestamp = 4, - SvfopCurrentTimestampN = 5, - SvfopLocaltime = 6, - SvfopLocaltimeN = 7, - SvfopLocaltimestamp = 8, - SvfopLocaltimestampN = 9, - SvfopCurrentRole = 10, - SvfopCurrentUser = 11, - SvfopUser = 12, - SvfopSessionUser = 13, - SvfopCurrentCatalog = 14, - SvfopCurrentSchema = 15, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum XmlExprOp { - Undefined = 0, - IsXmlconcat = 1, - IsXmlelement = 2, - IsXmlforest = 3, - IsXmlparse = 4, - IsXmlpi = 5, - IsXmlroot = 6, - IsXmlserialize = 7, - IsDocument = 8, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum XmlOptionType { - Undefined = 0, - XmloptionDocument = 1, - XmloptionContent = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum NullTestType { - Undefined = 0, - IsNull = 1, - IsNotNull = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum BoolTestType { - Undefined = 0, - IsTrue = 1, - IsNotTrue = 2, - IsFalse = 3, - IsNotFalse = 4, - IsUnknown = 5, - IsNotUnknown = 6, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum CmdType { - Undefined = 0, - CmdUnknown = 1, - CmdSelect = 2, - CmdUpdate = 3, - CmdInsert = 4, - CmdDelete = 5, - CmdUtility = 6, - CmdNothing = 7, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum JoinType { - Undefined = 0, - JoinInner = 1, - JoinLeft = 2, - JoinFull = 3, - JoinRight = 4, - JoinSemi = 5, - JoinAnti = 6, - JoinUniqueOuter = 7, - JoinUniqueInner = 8, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AggStrategy { - Undefined = 0, - AggPlain = 1, - AggSorted = 2, - AggHashed = 3, - AggMixed = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum AggSplit { - Undefined = 0, - AggsplitSimple = 1, - AggsplitInitialSerial = 2, - AggsplitFinalDeserial = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SetOpCmd { - Undefined = 0, - SetopcmdIntersect = 1, - SetopcmdIntersectAll = 2, - SetopcmdExcept = 3, - SetopcmdExceptAll = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum SetOpStrategy { - Undefined = 0, - SetopSorted = 1, - SetopHashed = 2, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum OnConflictAction { - Undefined = 0, - OnconflictNone = 1, - OnconflictNothing = 2, - OnconflictUpdate = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LimitOption { - Undefined = 0, - Default = 1, - Count = 2, - WithTies = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LockClauseStrength { - Undefined = 0, - LcsNone = 1, - LcsForkeyshare = 2, - LcsForshare = 3, - LcsFornokeyupdate = 4, - LcsForupdate = 5, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LockWaitPolicy { - Undefined = 0, - LockWaitBlock = 1, - LockWaitSkip = 2, - LockWaitError = 3, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum LockTupleMode { - Undefined = 0, - LockTupleKeyShare = 1, - LockTupleShare = 2, - LockTupleNoKeyExclusive = 3, - LockTupleExclusive = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum KeywordKind { - NoKeyword = 0, - UnreservedKeyword = 1, - ColNameKeyword = 2, - TypeFuncNameKeyword = 3, - ReservedKeyword = 4, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[repr(i32)] -pub enum Token { - Nul = 0, - /// Single-character tokens that are returned 1:1 (identical with "self" list in scan.l) - /// Either supporting syntax, or single-character operators (some can be both) - /// Also see <https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-SPECIAL-CHARS> - /// - /// "%" - Ascii37 = 37, - /// "(" - Ascii40 = 40, - /// ")" - Ascii41 = 41, - /// "*" - Ascii42 = 42, - /// "+" - Ascii43 = 43, - /// "," - Ascii44 = 44, - /// "-" - Ascii45 = 45, - /// "." - Ascii46 = 46, - /// "/" - Ascii47 = 47, - /// ":" - Ascii58 = 58, - /// ";" - Ascii59 = 59, - /// "<" - Ascii60 = 60, - /// "=" - Ascii61 = 61, - /// ">" - Ascii62 = 62, - /// "?" - Ascii63 = 63, - /// "[" - Ascii91 = 91, - /// "\" - Ascii92 = 92, - /// "]" - Ascii93 = 93, - /// "^" - Ascii94 = 94, - /// Named tokens in scan.l - Ident = 258, - Uident = 259, - Fconst = 260, - Sconst = 261, - Usconst = 262, - Bconst = 263, - Xconst = 264, - Op = 265, - Iconst = 266, - Param = 267, - Typecast = 268, - DotDot = 269, - ColonEquals = 270, - EqualsGreater = 271, - LessEquals = 272, - GreaterEquals = 273, - NotEquals = 274, - SqlComment = 275, - CComment = 276, - AbortP = 277, - AbsoluteP = 278, - Access = 279, - Action = 280, - AddP = 281, - Admin = 282, - After = 283, - Aggregate = 284, - All = 285, - Also = 286, - Alter = 287, - Always = 288, - Analyse = 289, - Analyze = 290, - And = 291, - Any = 292, - Array = 293, - As = 294, - Asc = 295, - Assertion = 296, - Assignment = 297, - Asymmetric = 298, - At = 299, - Attach = 300, - Attribute = 301, - Authorization = 302, - Backward = 303, - Before = 304, - BeginP = 305, - Between = 306, - Bigint = 307, - Binary = 308, - Bit = 309, - BooleanP = 310, - Both = 311, - By = 312, - Cache = 313, - Call = 314, - Called = 315, - Cascade = 316, - Cascaded = 317, - Case = 318, - Cast = 319, - CatalogP = 320, - Chain = 321, - CharP = 322, - Character = 323, - Characteristics = 324, - Check = 325, - Checkpoint = 326, - Class = 327, - Close = 328, - Cluster = 329, - Coalesce = 330, - Collate = 331, - Collation = 332, - Column = 333, - Columns = 334, - Comment = 335, - Comments = 336, - Commit = 337, - Committed = 338, - Concurrently = 339, - Configuration = 340, - Conflict = 341, - Connection = 342, - Constraint = 343, - Constraints = 344, - ContentP = 345, - ContinueP = 346, - ConversionP = 347, - Copy = 348, - Cost = 349, - Create = 350, - Cross = 351, - Csv = 352, - Cube = 353, - CurrentP = 354, - CurrentCatalog = 355, - CurrentDate = 356, - CurrentRole = 357, - CurrentSchema = 358, - CurrentTime = 359, - CurrentTimestamp = 360, - CurrentUser = 361, - Cursor = 362, - Cycle = 363, - DataP = 364, - Database = 365, - DayP = 366, - Deallocate = 367, - Dec = 368, - DecimalP = 369, - Declare = 370, - Default = 371, - Defaults = 372, - Deferrable = 373, - Deferred = 374, - Definer = 375, - DeleteP = 376, - Delimiter = 377, - Delimiters = 378, - Depends = 379, - Desc = 380, - Detach = 381, - Dictionary = 382, - DisableP = 383, - Discard = 384, - Distinct = 385, - Do = 386, - DocumentP = 387, - DomainP = 388, - DoubleP = 389, - Drop = 390, - Each = 391, - Else = 392, - EnableP = 393, - Encoding = 394, - Encrypted = 395, - EndP = 396, - EnumP = 397, - Escape = 398, - Event = 399, - Except = 400, - Exclude = 401, - Excluding = 402, - Exclusive = 403, - Execute = 404, - Exists = 405, - Explain = 406, - Expression = 407, - Extension = 408, - External = 409, - Extract = 410, - FalseP = 411, - Family = 412, - Fetch = 413, - Filter = 414, - FirstP = 415, - FloatP = 416, - Following = 417, - For = 418, - Force = 419, - Foreign = 420, - Forward = 421, - Freeze = 422, - From = 423, - Full = 424, - Function = 425, - Functions = 426, - Generated = 427, - Global = 428, - Grant = 429, - Granted = 430, - Greatest = 431, - GroupP = 432, - Grouping = 433, - Groups = 434, - Handler = 435, - Having = 436, - HeaderP = 437, - Hold = 438, - HourP = 439, - IdentityP = 440, - IfP = 441, - Ilike = 442, - Immediate = 443, - Immutable = 444, - ImplicitP = 445, - ImportP = 446, - InP = 447, - Include = 448, - Including = 449, - Increment = 450, - Index = 451, - Indexes = 452, - Inherit = 453, - Inherits = 454, - Initially = 455, - InlineP = 456, - InnerP = 457, - Inout = 458, - InputP = 459, - Insensitive = 460, - Insert = 461, - Instead = 462, - IntP = 463, - Integer = 464, - Intersect = 465, - Interval = 466, - Into = 467, - Invoker = 468, - Is = 469, - Isnull = 470, - Isolation = 471, - Join = 472, - Key = 473, - Label = 474, - Language = 475, - LargeP = 476, - LastP = 477, - LateralP = 478, - Leading = 479, - Leakproof = 480, - Least = 481, - Left = 482, - Level = 483, - Like = 484, - Limit = 485, - Listen = 486, - Load = 487, - Local = 488, - Localtime = 489, - Localtimestamp = 490, - Location = 491, - LockP = 492, - Locked = 493, - Logged = 494, - Mapping = 495, - Match = 496, - Materialized = 497, - Maxvalue = 498, - Method = 499, - MinuteP = 500, - Minvalue = 501, - Mode = 502, - MonthP = 503, - Move = 504, - NameP = 505, - Names = 506, - National = 507, - Natural = 508, - Nchar = 509, - New = 510, - Next = 511, - Nfc = 512, - Nfd = 513, - Nfkc = 514, - Nfkd = 515, - No = 516, - None = 517, - Normalize = 518, - Normalized = 519, - Not = 520, - Nothing = 521, - Notify = 522, - Notnull = 523, - Nowait = 524, - NullP = 525, - Nullif = 526, - NullsP = 527, - Numeric = 528, - ObjectP = 529, - Of = 530, - Off = 531, - Offset = 532, - Oids = 533, - Old = 534, - On = 535, - Only = 536, - Operator = 537, - Option = 538, - Options = 539, - Or = 540, - Order = 541, - Ordinality = 542, - Others = 543, - OutP = 544, - OuterP = 545, - Over = 546, - Overlaps = 547, - Overlay = 548, - Overriding = 549, - Owned = 550, - Owner = 551, - Parallel = 552, - Parser = 553, - Partial = 554, - Partition = 555, - Passing = 556, - Password = 557, - Placing = 558, - Plans = 559, - Policy = 560, - Position = 561, - Preceding = 562, - Precision = 563, - Preserve = 564, - Prepare = 565, - Prepared = 566, - Primary = 567, - Prior = 568, - Privileges = 569, - Procedural = 570, - Procedure = 571, - Procedures = 572, - Program = 573, - Publication = 574, - Quote = 575, - Range = 576, - Read = 577, - Real = 578, - Reassign = 579, - Recheck = 580, - Recursive = 581, - Ref = 582, - References = 583, - Referencing = 584, - Refresh = 585, - Reindex = 586, - RelativeP = 587, - Release = 588, - Rename = 589, - Repeatable = 590, - Replace = 591, - Replica = 592, - Reset = 593, - Restart = 594, - Restrict = 595, - Returning = 596, - Returns = 597, - Revoke = 598, - Right = 599, - Role = 600, - Rollback = 601, - Rollup = 602, - Routine = 603, - Routines = 604, - Row = 605, - Rows = 606, - Rule = 607, - Savepoint = 608, - Schema = 609, - Schemas = 610, - Scroll = 611, - Search = 612, - SecondP = 613, - Security = 614, - Select = 615, - Sequence = 616, - Sequences = 617, - Serializable = 618, - Server = 619, - Session = 620, - SessionUser = 621, - Set = 622, - Sets = 623, - Setof = 624, - Share = 625, - Show = 626, - Similar = 627, - Simple = 628, - Skip = 629, - Smallint = 630, - Snapshot = 631, - Some = 632, - SqlP = 633, - Stable = 634, - StandaloneP = 635, - Start = 636, - Statement = 637, - Statistics = 638, - Stdin = 639, - Stdout = 640, - Storage = 641, - Stored = 642, - StrictP = 643, - StripP = 644, - Subscription = 645, - Substring = 646, - Support = 647, - Symmetric = 648, - Sysid = 649, - SystemP = 650, - Table = 651, - Tables = 652, - Tablesample = 653, - Tablespace = 654, - Temp = 655, - Template = 656, - Temporary = 657, - TextP = 658, - Then = 659, - Ties = 660, - Time = 661, - Timestamp = 662, - To = 663, - Trailing = 664, - Transaction = 665, - Transform = 666, - Treat = 667, - Trigger = 668, - Trim = 669, - TrueP = 670, - Truncate = 671, - Trusted = 672, - TypeP = 673, - TypesP = 674, - Uescape = 675, - Unbounded = 676, - Uncommitted = 677, - Unencrypted = 678, - Union = 679, - Unique = 680, - Unknown = 681, - Unlisten = 682, - Unlogged = 683, - Until = 684, - Update = 685, - User = 686, - Using = 687, - Vacuum = 688, - Valid = 689, - Validate = 690, - Validator = 691, - ValueP = 692, - Values = 693, - Varchar = 694, - Variadic = 695, - Varying = 696, - Verbose = 697, - VersionP = 698, - View = 699, - Views = 700, - Volatile = 701, - When = 702, - Where = 703, - WhitespaceP = 704, - Window = 705, - With = 706, - Within = 707, - Without = 708, - Work = 709, - Wrapper = 710, - Write = 711, - XmlP = 712, - Xmlattributes = 713, - Xmlconcat = 714, - Xmlelement = 715, - Xmlexists = 716, - Xmlforest = 717, - Xmlnamespaces = 718, - Xmlparse = 719, - Xmlpi = 720, - Xmlroot = 721, - Xmlserialize = 722, - Xmltable = 723, - YearP = 724, - YesP = 725, - Zone = 726, - NotLa = 727, - NullsLa = 728, - WithLa = 729, - Postfixop = 730, - Uminus = 731, -} diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 503df53704793..9615c4db6b4b5 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -96,9 +96,25 @@ mod os_impl { #[cfg(unix)] pub fn check(path: &Path, bad: &mut bool) { + const ALLOWED: &[&str] = &["configure"]; + crate::walk_no_read( path, - &mut |path| crate::filter_dirs(path) || path.ends_with("src/etc"), + &mut |path| { + crate::filter_dirs(path) + || path.ends_with("src/etc") + // This is a list of directories that we almost certainly + // don't need to walk. A future PR will likely want to + // remove these in favor of crate::walk_no_read using git + // ls-files to discover the paths we should check, which + // would naturally ignore all of these directories. It's + // also likely faster than walking the directory tree + // directly (since git is just reading from a couple files + // to produce the results). + || path.ends_with("target") + || path.ends_with("build") + || path.ends_with(".git") + }, &mut |entry| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); @@ -110,6 +126,11 @@ mod os_impl { if t!(is_executable(&file), file) { let rel_path = file.strip_prefix(path).unwrap(); let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); + + if ALLOWED.contains(&git_friendly_path.as_str()) { + return; + } + let output = Command::new("git") .arg("ls-files") .arg(&git_friendly_path) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 7775bbb13e88a..55cf3fee9bf11 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -63,6 +63,10 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ ("target-lexicon", "Apache-2.0 WITH LLVM-exception"), ]; +const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[ + ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde +]; + /// These are the root crates that are part of the runtime. The licenses for /// these and all their dependencies *must not* be in the exception list. const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; @@ -96,7 +100,6 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "chalk-ir", "chalk-solve", "chrono", - "cmake", "compiler_builtins", "cpufeatures", "crc32fast", @@ -309,7 +312,13 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { let metadata = t!(cmd.exec()); let runtime_ids = compute_runtime_crates(&metadata); check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad); - check_dependencies(&metadata, PERMITTED_DEPENDENCIES, RESTRICTED_DEPENDENCY_CRATES, bad); + check_dependencies( + &metadata, + "main workspace", + PERMITTED_DEPENDENCIES, + RESTRICTED_DEPENDENCY_CRATES, + bad, + ); check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad); check_rustfix(&metadata, bad); @@ -323,11 +332,20 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { check_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad); check_dependencies( &metadata, + "cranelift", PERMITTED_CRANELIFT_DEPENDENCIES, &["rustc_codegen_cranelift"], bad, ); check_crate_duplicate(&metadata, &[], bad); + + let mut cmd = cargo_metadata::MetadataCommand::new(); + cmd.cargo_path(cargo) + .manifest_path(root.join("src/bootstrap/Cargo.toml")) + .features(cargo_metadata::CargoOpt::AllFeatures); + let metadata = t!(cmd.exec()); + let runtime_ids = HashSet::new(); + check_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad); } /// Check that all licenses are in the valid list in `LICENSES`. @@ -409,6 +427,7 @@ fn check_exceptions( /// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`. fn check_dependencies( metadata: &Metadata, + descr: &str, permitted_dependencies: &[&'static str], restricted_dependency_crates: &[&'static str], bad: &mut bool, @@ -438,7 +457,7 @@ fn check_dependencies( } if !unapproved.is_empty() { - tidy_error!(bad, "Dependencies not explicitly permitted:"); + tidy_error!(bad, "Dependencies for {} not explicitly permitted:", descr); for dep in unapproved { println!("* {dep}"); } diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index e56ce3329cc47..4ffa1fa8b28d3 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -11,7 +11,7 @@ use regex::Regex; // A few of those error codes can't be tested but all the others can and *should* be tested! const EXEMPTED_FROM_TEST: &[&str] = &[ "E0279", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519", - "E0523", "E0554", "E0640", "E0717", "E0729", + "E0523", "E0554", "E0640", "E0717", "E0729", "E0789", ]; // Some error codes don't have any tests apparently... diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index d555f7c8e34ff..aa8d8b4f64d7d 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -78,13 +78,8 @@ fn main() { check!(unit_tests, &compiler_path); check!(unit_tests, &library_path); - if bins::check_filesystem_support( - &[&src_path, &compiler_path, &library_path], - &output_directory, - ) { - check!(bins, &src_path); - check!(bins, &compiler_path); - check!(bins, &library_path); + if bins::check_filesystem_support(&[&root_path], &output_directory) { + check!(bins, &root_path); } check!(style, &src_path); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 5a061009b6b95..3cf44a2d7d1ef 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -395,9 +395,6 @@ pub fn check(path: &Path, bad: &mut bool) { ); }; suppressible_tidy_err!(err, skip_file_length, ""); - } else if lines > (LINES * 7) / 10 { - // Just set it to something that doesn't trigger the "unnecessarily ignored" warning. - skip_file_length = Directive::Ignore(true); } if let Directive::Ignore(false) = skip_cr { @@ -406,12 +403,6 @@ pub fn check(path: &Path, bad: &mut bool) { if let Directive::Ignore(false) = skip_tab { tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display()); } - if let Directive::Ignore(false) = skip_line_length { - tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display()); - } - if let Directive::Ignore(false) = skip_file_length { - tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display()); - } if let Directive::Ignore(false) = skip_end_whitespace { tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display()); } @@ -424,5 +415,9 @@ pub fn check(path: &Path, bad: &mut bool) { if let Directive::Ignore(false) = skip_copyright { tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display()); } + // We deliberately do not warn about these being unnecessary, + // that would just lead to annoying churn. + let _unused = skip_line_length; + let _unused = skip_file_length; }) } diff --git a/src/version b/src/version index af92bdd9f58d1..9405730420ffc 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.63.0 +1.64.0 diff --git a/triagebot.toml b/triagebot.toml index cef78cc3b336e..f2930b50e3ee8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -165,6 +165,19 @@ exclude_labels = [ "T-*", ] +[autolabel."A-bootstrap"] +trigger_files = [ + "x.py", + "src/bootstrap", + "src/tools/rust-installer", +] + +[autolabel."T-infra"] +trigger_files = [ + "src/ci", + "src/tools/bump-stage0", +] + [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts topic = "#{number} {title}" @@ -215,3 +228,116 @@ changelog-path = "RELEASES.md" changelog-branch = "master" [shortcut] + + +[mentions."compiler/rustc_apfloat"] +message = """ +Changes rustc_apfloat. rustc_apfloat is currently in limbo and you almost \ +certainly don't want to change it (see #55993). +""" +cc = ["@eddyb"] + +[mentions."compiler/rustc_codegen_cranelift"] +cc = ["@bjorn3"] + +[mentions."compiler/rustc_codegen_gcc"] +cc = ["@antoyo"] + +[mentions."compiler/rustc_const_eval/src/interpret"] +message = "Some changes occurred to the CTFE / Miri engine" +cc = ["@rust-lang/miri"] + +[mentions."compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs"] +message = "Some changes occurred in need_type_info.rs" +cc = ["@lcnr"] + +[mentions."compiler/rustc_middle/src/mir/interpret"] +message = "Some changes occurred to the CTFE / Miri engine" +cc = ["@rust-lang/miri"] + +[mentions."compiler/rustc_mir_transform/src/"] +message = "Some changes occurred to MIR optimizations" +cc = ["@rust-lang/wg-mir-opt"] + +[mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"] +message = "Some changes occurred in const_evaluatable.rs" +cc = ["@lcnr"] + +[mentions."compiler/rustc_error_codes/src/error_codes.rs"] +message = "Some changes occurred in diagnostic error codes" +cc = ["@GuillaumeGomez"] + +[mentions."library"] +message = """ +Hey! It looks like you've submitted a new PR for the library teams! + +If this PR contains changes to any `rust-lang/rust` public library APIs then \ +please comment with `@rustbot label +T-libs-api -T-libs` to tag it \ +appropriately. If this PR contains changes to any unstable APIs please edit \ +the PR description to add a link to the relevant [API Change \ +Proposal](https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html) \ +or [create one](https://github.com/rust-lang/libs-team/issues/new?assignees=&labels=api-change-proposal%2C+T-libs-api&template=api-change-proposal.md&title=%28My+API+Change+Proposal%29) \ +if you haven't already. If you're unsure where your change falls no worries, \ +just leave it as is and the reviewer will take a look and make a decision to \ +forward on if necessary. + +Examples of `T-libs-api` changes: + +* Stabilizing library features +* Introducing insta-stable changes such as new implementations of existing \ + stable traits on existing stable types +* Introducing new or changing existing unstable library APIs (excluding \ + permanently unstable features / features without a tracking issue) +* Changing public documentation in ways that create new stability guarantees +* Changing observable runtime behavior of library APIs +""" + +[mentions."library/proc_macro/src/bridge"] +cc = ["@rust-lang/wg-rls-2"] + +[mentions."src/librustdoc/clean/types.rs"] +cc = ["@camelid"] + +[mentions."src/librustdoc/html/static"] +message = "Some changes occurred in HTML/CSS/JS." +cc = [ + "@GuillaumeGomez", + "@Folyd", + "@jsha", +] + +[mentions."src/librustdoc/html/static/css/themes"] +message = "Some changes occurred in HTML/CSS themes." +cc = ["@GuillaumeGomez"] + +[mentions."src/librustdoc/html/static/css/themes/ayu.css"] +message = "A change occurred in the Ayu theme." +cc = ["@Cldfire"] + +[mentions."src/rustdoc-json-types"] +message = """ +rustdoc-json-types is a **public** (although nightly-only) API. \ +If possible, consider changing `src/librustdoc/json/conversions.rs`; \ +otherwise, make sure you bump the `FORMAT_VERSION` constant. +""" +cc = [ + "@CraftSpider", + "@aDotInTheVoid", +] + +[mentions."src/tools/cargo"] +cc = ["@ehuss"] + +[mentions."src/tools/clippy"] +cc = ["@rust-lang/clippy"] + +[mentions."src/tools/miri"] +message = "The Miri submodule was changed" +cc = ["@rust-lang/miri"] + +[mentions."src/tools/rustfmt"] +cc = ["@rust-lang/rustfmt"] + +[mentions."compiler/rustc_middle/src/mir/syntax.rs"] +message = "This PR changes MIR" +cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakaras"] diff --git a/x.py b/x.py index 4f64ea9fae8b8..0289056fdcb16 100755 --- a/x.py +++ b/x.py @@ -1,5 +1,25 @@ -#!/usr/bin/env python +#!/usr/bin/env bash +# Modern Linux and macOS systems commonly only have a thing called `python3` and +# not `python`, while Windows commonly does not have `python3`, so we cannot +# directly use python in the shebang and have it consistently work. Instead we +# embed some bash to look for a python to run the rest of the script. +# +# On Windows, `py -3` sometimes works. We need to try it first because `python3` +# sometimes tries to launch the app store on Windows. +'''': +for PYTHON in "py -3" python3 python python2; do + if command -v $PYTHON >/dev/null; then + exec $PYTHON "$0" "$@" + break + fi +done +echo "$0: error: did not find python installed" >&2 +exit 1 +''' + +# The rest of this file is Python. +# # This file is only a "symlink" to bootstrap.py, all logic should go there. import os @@ -7,11 +27,12 @@ # If this is python2, check if python3 is available and re-execute with that # interpreter. +# +# `./x.py` would not normally benefit from this because the bash above tries +# python3 before 2, but this matters if someone ran `python x.py` and their +# system's `python` is python2. if sys.version_info.major < 3: try: - # On Windows, `py -3` sometimes works. - # Try this first, because 'python3' sometimes tries to launch the app - # store on Windows os.execvp("py", ["py", "-3"] + sys.argv) except OSError: try: